Come leggere il codice HTML come XML e ottenere l'output come l'esempio in sql?


11

Ho un codice HTML archiviato nel database e voglio leggerlo come XML.

I miei codici:

http://rextester.com/RMEHO89992

Questo è un esempio del codice HTML che ho:

<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>

e questo è un esempio dell'output di cui ho bisogno:

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

Ho bisogno di ottenere il valore all'interno del <h4>tag come a Category, il primo <span>tag come Selezione e il resto dei valori come stringa concatenata.

Ho provato la seguente query:

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) 

e :

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)

Ma ottiene solo la prima categoria e non riunisce tutti i valori.

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 

Possono esserci N categorie e i valori potrebbero essere o meno all'interno dei <span>tag. Come posso ottenere tutte le categorie con il loro valore corrispondente? o ottieni:

category              h4 number
--------            -----------
 A                     1
 B                     2
  • 1, media = h4 prima, 2, media = h4 secondi
 ul number         Selection        Value                    
    ---------        ---------        ------------             
    1                Ab               AD                  
    1                Ag               AL                       
    2                Bb               BD                   
    2                Bg               BL       

relazione tra il numero ul della colonna e il numero h4. non posso.


1
Sei sicuro che il risultato atteso sia corretto? Non dovrebbe essere AD ACper la prima riga nella terza colonna?
Mikael Eriksson,

Sto cercando di stabilire la comunicazione tra i nodi `h4` e` ul`.
RedArmy,

Risposte:


7

Questo non è esattamente elegante ma sembra fare il lavoro.

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

Che ritorna

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

Suppongo che questo sia ciò che desideri poiché la tabella dei risultati desiderata nella domanda non restituisce il "resto dei valori come stringa concatenata"


14

Sto cercando di stabilire la comunicazione tra i nodi h4e ul.

È possibile utilizzare l' operatore <<e >>per verificare se un nodo si trova prima o dopo un altro nodo nell'ordine del documento. Combina questo con un predicato sulla posizione, [1]per ottenere la prima occorrenza anche nell'ordine del documento.

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:

<<e >>sono chiamati Operatori di confronto ordini nodo

Se hai un frammento XML come questo:

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

puoi ottenere tutti i nodi prima della prima occorrenza di N3con questa query:

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

Risultato:

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

/*ti darà tutti i nodi root. Ciò che è racchiuso in []un predicato. .è il nodo corrente ed /N3[1]è il primo nodo N3 in ordine di documento a livello di radice. Quindi da ogni nodo radice si ottengono i nodi che precedono N3.

Ecco quasi la stessa query, solo tu ottieni i nodi che seguono il primo N3nodo:

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

Per ottenere il primo nodo solo dopo il primo N3nodo, aggiungi il predicato [1]:

select @X.query('/*[. >> /N3[1]][1]');
<N4>4</N4>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.