【问题标题】:Parse XML into SQL Server table and keep XHTML markup within XML element将 XML 解析为 SQL Server 表并将 XHTML 标记保留在 XML 元素中
【发布时间】:2020-11-11 20:33:49
【问题描述】:

这个问题是 XML 文件中有 xhtml 标记(请参阅 Example_Code 元素),当我运行 XQuery 时,它似乎去除了标记并只保留了文本。我想将 Example_Code 的值完全存储在 XML 文件中的表中。 非常感谢您的阅读。

DECLARE @Xml XML = 
N'
<Demonstrative_Examples xmlns:xhtml="http://www.w3.org/1999/xhtml">>
    <Demonstrative_Example>
        <Intro_Text>This is the intro</Intro_Text>
        <Example_Code Nature="bad">Example 1.1</Example_Code>
        <Body_Text>Body 1.1</Body_Text>
        <Example_Code>   <xhtml:div>String sessionID = generateSessionId();<xhtml:br/>Cookie c = new Cookie("session_id", sessionID);<xhtml:br/>response.addCookie(c);</xhtml:div>
</Example_Code>
    </Demonstrative_Example>
    <Demonstrative_Example>
        <Intro_Text>This is the 2nd intro</Intro_Text>
        <Body_Text>Body 2.1</Body_Text>
        <Example_Code Nature="Good">Example 2.1</Example_Code>
    </Demonstrative_Example>
</Demonstrative_Examples>';

-- just to see
;WITH XMLNAMESPACES ('http://www.w3.org/1999/xhtml' as xhtml)  
SELECT @xml.query('<root>
{
    for $x in /Demonstrative_Examples/Demonstrative_Example
    let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
        for $y in $x/*[position() gt 1]
        let $pos := count($x/*[. << $y[1]]) + 1
        let $it := $x/*[local-name()="Intro_Text"]
        return <r id="{$id}" pos="{$pos - 1}" 
            Intro_Text="{$it}" 
            Body_Text="{$y[local-name()="Body_Text"]/text()}" 
            Example_Code="{$y[local-name()="Example_Code"]}"
            Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
}
</root>') AS xmldata;

-- real deal
;WITH rs AS
(
    SELECT @xml.query('<root>
    {
        for $x in /Demonstrative_Examples/Demonstrative_Example
        let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
            for $y in $x/*[position() gt 1]
            let $pos := count($x/*[. << $y[1]]) + 1
            let $it := $x/*[local-name()="Intro_Text"]
            return <r id="{$id}" pos="{$pos - 1}" 
                Intro_Text="{$it}" 
                Body_Text="{$y[local-name()="Body_Text"]/text()}" 
                Example_Code="{$y[local-name()="Example_Code"]/text()}"
                Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
    }
    </root>') AS xmldata
)
SELECT c.value('@id', 'INT') AS [ID] 
    , c.value('@pos', 'INT') AS [Order]
    , c.value('@Intro_Text', 'VARCHAR(30)') AS [Intro_Text]
    , c.value('@Body_Text', 'VARCHAR(30)') AS [Body_Text]
    , c.value('@Example_Code', 'VARCHAR(30)') AS [Example_Code]
    , c.value('@Nature', 'VARCHAR(30)') AS [Nature]
FROM rs CROSS APPLY xmldata.nodes('/root/r') AS t(c);

这是结果集:

【问题讨论】:

    标签: sql-server xml


    【解决方案1】:
    declare @Xml XML = 
    N'
    <Demonstrative_Examples xmlns:xhtml="http://www.w3.org/1999/xhtml">
        <Demonstrative_Example>
            <Intro_Text>This is the intro</Intro_Text>
            <Example_Code Nature="Bad">Example 1.1</Example_Code>
            <Body_Text>Body 1.1</Body_Text>
            <Example_Code><xhtml:div>String sessionID = generateSessionId();<xhtml:br/>Cookie c = new Cookie("session_id", sessionID);<xhtml:br/>response.addCookie(c);</xhtml:div></Example_Code>
        </Demonstrative_Example>
        <Demonstrative_Example>
            <Intro_Text>This is the 2nd intro</Intro_Text>
            <Body_Text>Body 2.1</Body_Text>
            <Example_Code Nature="Good">Example 2.1</Example_Code>
            <e4>e4</e4>        
            <e5>e5</e5>
            <e6>e6</e6>
            <e7>e7</e7>
            <e8>e8</e8>                        
            <Example_Code Nature="Ugly">examplecode position9 <xhtml:div>String sessionID = generateSessionId();<xhtml:br/>Cookie c = new Cookie("session_id", sessionID);<xhtml:br/>response.addCookie(c);</xhtml:div></Example_Code>
        </Demonstrative_Example>
    </Demonstrative_Examples>';
    
    select 
        s.example_order_id,
        s.position_in_example,
        case s.elementname when N'Intro_Text' then s.nodecontent end as IntroText,
        case s.elementname when N'Example_Code' then s.nodecontent end as ExampleCode,
        case s.elementname when N'Body_Text' then s.nodecontent end as BodyText,
        case s.elementname when N'Example_Code' then s.attributenature end as ExampleNature 
    from
    (
        select 
            dense_rank() over(order by d.ex) as example_order_id,
            row_number() over(partition by d.ex order by ex.el) as position_in_example,
            ex.el.value('local-name(.)[1]', 'nvarchar(100)') as elementname,
            ex.el.value('@Nature[1]', 'nvarchar(30)') as attributenature,
            cast(ex.el.query('node()') as nvarchar(max)) as nodecontent
        from @Xml.nodes('Demonstrative_Examples/Demonstrative_Example') as d(ex)
        outer apply d.ex.nodes('*') as ex(el)
    ) as s
    where s.elementname in (N'Intro_Text', N'Example_Code', N'Body_Text');
    

    【讨论】:

      【解决方案2】:

      要在 XHTML/XML 时保留 &lt;Example_Code&gt; 元素值,您需要在源 XML 中使用 CDATA 部分。请看下文。

      我做了一些额外的修改:

      • 已注释掉命名空间声明。在这种情况下不需要它。
      • 将@Example_Code 的大小增加到VARCHAR(MAX) 以容纳冗长的值。

      SQL

      DECLARE @Xml XML = 
      N'<Demonstrative_Examples xmlns:xhtml="http://www.w3.org/1999/xhtml">
          <Demonstrative_Example>
              <Intro_Text>This is the intro</Intro_Text>
              <Example_Code Nature="bad">Example 1.1</Example_Code>
              <Body_Text>Body 1.1</Body_Text>
              <Example_Code><![CDATA[
                  <xhtml:div>String sessionID = generateSessionId();<xhtml:br/>Cookie c = new Cookie("session_id", sessionID);<xhtml:br/>response.addCookie(c);</xhtml:div>
              ]]>
              </Example_Code>
          </Demonstrative_Example>
          <Demonstrative_Example>
              <Intro_Text>This is the 2nd intro</Intro_Text>
              <Body_Text>Body 2.1</Body_Text>
              <Example_Code Nature="Good">Example 2.1</Example_Code>
          </Demonstrative_Example>
      </Demonstrative_Examples>';
      
      -- just to see
      --;WITH XMLNAMESPACES ('http://www.w3.org/1999/xhtml' as xhtml)  
      SELECT @xml.query('<root>
      {
          for $x in /Demonstrative_Examples/Demonstrative_Example
          let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
          let $it := $x/*[local-name()="Intro_Text"]
              for $y in $x/*[position() gt 1]
              let $pos := count($x/*[. << $y[1]]) + 1
              return <r id="{$id}" pos="{$pos - 1}" 
                  Intro_Text="{$it}" 
                  Body_Text="{$y[local-name()="Body_Text"]/text()}" 
                  Example_Code="{$y[local-name()="Example_Code"]}"
                  Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
      }
      </root>') AS xmldata;
      
      -- real deal
      ;WITH rs AS
      (
          SELECT @xml.query('<root>
          {
              for $x in /Demonstrative_Examples/Demonstrative_Example
              let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
              let $it := $x/*[local-name()="Intro_Text"]
                  for $y in $x/*[position() gt 1]
                  let $pos := count($x/*[. << $y[1]]) + 1
                  return <r id="{$id}" pos="{$pos - 1}" 
                      Intro_Text="{$it}" 
                      Body_Text="{$y[local-name()="Body_Text"]/text()}" 
                      Example_Code="{$y[local-name()="Example_Code"]/text()}"
                      Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
          }
          </root>') AS xmldata
      )
      SELECT c.value('@id', 'INT') AS [ID] 
          , c.value('@pos', 'INT') AS [Order]
          , c.value('@Intro_Text', 'VARCHAR(30)') AS [Intro_Text]
          , c.value('@Body_Text', 'VARCHAR(30)') AS [Body_Text]
          , c.value('@Example_Code', 'VARCHAR(MAX)') AS [Example_Code]
          , c.value('@Nature', 'VARCHAR(30)') AS [Nature]
      FROM rs CROSS APPLY xmldata.nodes('/root/r') AS t(c);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-23
        • 1970-01-01
        相关资源
        最近更新 更多