如何将 HTML 代码读取为 XML 并像 sql 中的示例一样获得输出?

Red*_*rmy 11 xml sql-server t-sql

我在数据库中存储了 HTML 代码,我想将其作为 XML 读取。

我的代码:

http://rextester.com/RMEHO89992

这是我拥有的 HTML 代码示例:

<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>
Run Code Online (Sandbox Code Playgroud)

这是我需要的输出示例:

Category         Selection        Value                    
---------        ---------        ------------             
A                Ab               AD                  
A                Ag               AL                       
B                Bb               BD                   
B                Bg               BL                       
Run Code Online (Sandbox Code Playgroud)

我需要将<h4>标签内的值作为 a Category,第一个<span>标签作为 Selection ,其余的值作为连接字符串。

我试过以下查询:

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) 
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

但它只得到第一个类别,并没有得到所有的值。

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 
Run Code Online (Sandbox Code Playgroud)

可以有 N 个类别,值可能在也可能不在<span>标签内。如何获得所有类别及其相应的值?或得到:

category              h4 number
--------            -----------
 A                     1
 B                     2
Run Code Online (Sandbox Code Playgroud)
  • 1 ,mean = h4 第一 , 2 ,mean = h4 第二
 ul number         Selection        Value                    
    ---------        ---------        ------------             
    1                Ab               AD                  
    1                Ag               AL                       
    2                Bb               BD                   
    2                Bg               BL       
Run Code Online (Sandbox Code Playgroud)

列 ul 编号和 h4 编号之间的关系。我不能。

Mik*_*son 14

我正在尝试在节点h4ul.

您可以使用<<and>>运算符来检查一个节点是在文档顺序中的另一个节点之前还是之后。将其与位置的谓词结合,[1], 以获取文档顺序中的第一次出现。

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);
Run Code Online (Sandbox Code Playgroud)

雷克斯特:

<<>>称为节点顺序比较运算符

如果您有这样的 XML 片段:

<N1>1</N1>
<N2>2</N2>
<N3>3</N3>
<N4>4</N4>
<N5>5</N5>
Run Code Online (Sandbox Code Playgroud)

您可以N3使用此查询在第一次出现之前获取所有节点:

select @X.query('/*[. << /N3[1]]');
Run Code Online (Sandbox Code Playgroud)

结果:

<N1>1</N1>
<N2>2</N2>
Run Code Online (Sandbox Code Playgroud)

/*会给你所有的根节点。包含在其中的[]是谓词。.是当前节点,并且/N3[1]是根级别文档顺序中的第一个 N3 节点。因此,您可以从每个根节点获得在N3.

这是几乎相同的查询,只有你的节点遵循的第一N3点:

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

要仅获取第一个节点之后的第一个N3节点,请添加谓词[1]

select @X.query('/*[. >> /N3[1]][1]');
Run Code Online (Sandbox Code Playgroud)
<N4>4</N4>
Run Code Online (Sandbox Code Playgroud)


Mar*_*ith 7

这并不完全优雅,但似乎可以完成这项工作。

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
Run Code Online (Sandbox Code Playgroud)

哪个返回

+----------+-----------+-------+
| Category | Selection | Value |
+----------+-----------+-------+
|  A       |  Ab       | AD AC |
|  A       |  Ag       | AL    |
|  B       |  Bb       | BD BC |
|  B       |  Bg       | BL    |
+----------+-----------+-------+
Run Code Online (Sandbox Code Playgroud)

我假设这是您想要的,因为问题中所需的结果表不会返回“其余值作为连接字符串”