Wie lese ich HTML-Code als XML und erhalte die Ausgabe wie im Beispiel in SQL?

11

Ich habe HTML-Code in der Datenbank gespeichert und möchte ihn als XML lesen.

Meine Codes:

http://rextester.com/RMEHO89992

Dies ist ein Beispiel für den HTML-Code, den ich habe:

<div>
  <section>
       <h4>
         <span> A </span>
        </h4>
        <ul>
           <li>
              <span> Ab</span>
                     AD
              <span> AC </span>
           </li>
           <li>
              <span> Ag</span>
              <span> AL </span>
           </li>
        </ul>
        <h4>
              <span> B </span>
       </h4>
       <ul>
           <li>
              <span> Bb</span>
                     BD
              <span> BC </span>
           </li>
           <li>
              <span> Bg</span>
              <span> BL </span>
           </li>
        </ul>
   </section>
</div>

und dies ist ein Beispiel für die Ausgabe, die ich brauche:

Category         Selection        Value                    
---------        ---------        ------------             
A                Ab               AD                  
A                Ag               AL                       
B                Bb               BD                   
B                Bg               BL                       

Ich muss den Wert innerhalb des <h4>Tags als Category, das erste <span>Tag als Auswahl und den Rest der Werte als verkettete Zeichenfolge erhalten.

Ich habe die folgende Abfrage versucht:

SELECT 
    (  isnull(t.v.value('(h4/span/span[1]/text())[1]','nvarchar(max)'),'') 
     + isnull(t.v.value('(h4/span/text())[1]','nvarchar(max)'),'')
     + isnull(t.v.value('(h4/span/span[2]/text())[2]','nvarchar(max)'),'')
    ) AS [Category],
    (  isnull(c.g.value('(span[1]/text())[1]','nvarchar(max)'),'')
     + isnull(c.g.value('(span[1]/span/text())[1]','nvarchar(max)'),'')
     + isnull(c.g.value('(span[1]/text())[2]','nvarchar(max)'),'')
    ) AS [Selection],
    (  isnull(c.g.value('(span[2]/text())[1]','nvarchar(max)'),'')
     + isnull(c.g.value('(span[2]/span/text())[1]','nvarchar(max)'),'')
     + isnull(c.g.value('(span[2]/text())[2]','nvarchar(max)'),'')
    ) AS [Value]
FROM @htmlXML.nodes('div/section') as t(v)
CROSS APPLY t.v.nodes('./ul/li') AS c(g) 

und :

SELECT 
       t.v.value('.','nvarchar(max)')
       ,
     --( isnull(t.v.value('(h4/span/span[1]/text())[1]','nvarchar(max)'),'')+isnull(t.v.value('(h4/span/text())[1]','nvarchar(max)'),'')+isnull(t.v.value('(h4/span/span[2]/text())[2]','nvarchar(max)'),''))AS [Category],

          ( isnull(c.g.value('(span[1]/text())[1]','nvarchar(max)'),'')+isnull(c.g.value('(span[1]/span/text())[1]','nvarchar(max)'),'')+isnull(c.g.value('(span[1]/text())[2]','nvarchar(max)'),''))AS [Selection]

           ,
         ( isnull(c.g.value('(span[2]/text())[1]','nvarchar(max)'),'')+isnull(c.g.value('(span[2]/span/text())[1]','nvarchar(max)'),'')+isnull(c.g.value('(span[2]/text())[2]','nvarchar(max)'),''))AS [Value]
    FROM    @htmlXML.nodes('div/section/h4/span') as t(v)
    CROSS APPLY @htmlXML.nodes('div/section/ul/li') AS c(g)

Es wird jedoch nur die erste Kategorie und nicht alle Werte zusammen angezeigt.

Category         Selection        Value
---------        ---------        ------------
A                Ab               AC 
B                Ab               AC 
A                Ag               AL
B                Ag               AL 
A                Bb               BC
B                Bb               BC 
A                Bg               BL 
B                Bg               BL 

Es kann N Kategorien geben, und die Werte können sich innerhalb von <span>Tags befinden oder nicht . Wie kann ich alle Kategorien mit ihrem entsprechenden Wert erhalten? oder bekommen:

category              h4 number
--------            -----------
 A                     1
 B                     2
  • 1, Mittelwert = h4 zuerst, 2, Mittelwert = h4 Sekunde
 ul number         Selection        Value                    
    ---------        ---------        ------------             
    1                Ab               AD                  
    1                Ag               AL                       
    2                Bb               BD                   
    2                Bg               BL       

Beziehung zwischen Spalte ul Nummer und h4 Nummer. ich kann nicht.

Rote Armee
quelle
1
Sind Sie sicher, dass das erwartete Ergebnis korrekt ist? Sollte es nicht AD ACfür die erste Zeile in der dritten Spalte sein?
Mikael Eriksson
Ich versuche, die Kommunikation zwischen den Knoten "h4" und "ul" herzustellen.
RedArmy

Antworten:

7

Das ist nicht gerade elegant, scheint aber den Job zu machen.

DECLARE @X XML = REPLACE(REPLACE(@S, '<h4>', '<foo><h4>'), '</ul>', '</ul></foo>')

SELECT Category = x.value('../../h4[1]/span[1]', 'varchar(10)'),
       Selection = x.value('descendant-or-self::text()[1]', 'varchar(10)'),
       Value = REPLACE(
                REPLACE(
                 REPLACE(
                  LTRIM(
                   RTRIM(
                    REPLACE(
                     REPLACE(
                      CAST(x.x.query('fn:data(descendant-or-self::text()[fn:position() > 1])') AS VARCHAR(MAX))
                     , char(10), '')
                    , char(13), '')
                   )
                  )
                 , '  ', ' |')
                , '| ', '')
               , '|', '')
FROM   @X.nodes('div/section/foo/ul/li') x(x)
ORDER  BY Category,
          Selection

Welches kehrt zurück

+----------+-----------+-------+
| Category | Selection | Value |
+----------+-----------+-------+
|  A       |  Ab       | AD AC |
|  A       |  Ag       | AL    |
|  B       |  Bb       | BD BC |
|  B       |  Bg       | BL    |
+----------+-----------+-------+

Ich gehe davon aus, dass dies das ist, was Sie wollen, da die gewünschte Ergebnistabelle in der Frage nicht den "Rest der Werte als verkettete Zeichenfolge" zurückgibt.

Martin Smith
quelle
14

Ich versuche, die Kommunikation zwischen Knoten h4und herzustellen ul.

Sie können die Verwendung <<und >>Betreiber zu überprüfen , ob ein Knoten vor oder nach einem anderen Knoten in Dokumentreihenfolge ist. Kombinieren Sie dies mit einem Prädikat für die Position, [1]um das erste Vorkommen auch in der Reihenfolge der Dokumente zu erhalten.

select H4.X.value('(span/text())[1]', 'varchar(10)') as Section,
       UL.X.query('.') as UL
from @X.nodes('/div/section/h4') as H4(X)
  cross apply H4.X.nodes('(let $h4 := . (: Save current h4 node :)
                           return /div/section/ul[$h4 << .])[1]') as UL(X);

Rextester:

<<und >>werden als Knotenreihenfolge-Vergleichsoperatoren bezeichnet

Wenn Sie ein XML-Fragment wie dieses haben:

<N1>1</N1>
<N2>2</N2>
<N3>3</N3>
<N4>4</N4>
<N5>5</N5>

N3Mit dieser Abfrage können Sie alle Knoten vor dem ersten Auftreten abrufen:

select @X.query('/*[. << /N3[1]]');

Ergebnis:

<N1>1</N1>
<N2>2</N2>

/*gibt Ihnen alle Wurzelknoten. Was eingeschlossen []ist, ist ein Prädikat. .ist der aktuelle Knoten und /N3[1]der erste N3-Knoten in Dokumentreihenfolge auf Stammebene. Von jedem Wurzelknoten erhalten Sie also die vorhergehenden Knoten N3.

Hier ist fast die gleiche Abfrage, nur Sie erhalten die Knoten, die dem ersten N3Knoten folgen :

select @X.query('/*[. >> /N3[1]]');
<N4>4</N4>
<N5>5</N5>

Um nur den ersten Knoten nach dem ersten N3Knoten zu erhalten, fügen Sie das Prädikat hinzu [1]:

select @X.query('/*[. >> /N3[1]][1]');
<N4>4</N4>
Mikael Eriksson
quelle