【问题标题】:Retrieving All instances of an 3rd level XML field from an XML column从 XML 列中检索 3 级 XML 字段的所有实例
【发布时间】:2019-08-23 11:37:27
【问题描述】:

我的一个表中有一个 XML 数据字段,基本上如下所示:

<App xmlns='http://Namespace1'>
    <Package xmlns='http://Namespace2'>
        <Item>
            <ItemDetails xmlns='http://Namespace3'>
                <ItemName>ItemNameValue</ItemName>
            </ItemDetails>
            other_item_stuff
        </Item>
        <Item>
            <ItemDetails>
                    <ItemName>ItemNameValue</ItemName>
            </ItemDetails>
        </Item>
        ...
    </Package>
</App>

我需要从 XML 中获取所有 ItemNameValues。

我尝试根据我的目的调整网上找到的许多示例,但都失败了。我似乎能做的最好的事情是为每个包裹获得一个 ItemName。 我认为 CROSS APPLY 是我需要去的地方,但是检索所有 itemdetail.itemname 的语法却让我望而却步。

这是我最近的失败(不返回任何内容):

WITH XMLNAMESPACES(
'http://Namespace1' AS xsd,
'http://www.w3.org/2001/XMLSchema-instance' AS xsi,
'http://Namespace2' AS ns1,
'http://Namespace3' AS ns2)            
Items.d.value('(ns2:ItemDetails/ItemName/text())[1]','varchar(200)') as 
ItemName
FROM MyTable
CROSS APPLY XMLDataColumn.nodes('/xsd:App/ns1:Package/ns1:Item') Items(d)

我希望从每个 XML 字段中获取多条记录,但只能获取第一个元素。

【问题讨论】:

  • 您的查询表明您有命名空间,但您的 xml 不包含任何命名空间。是这个问题吗?
  • 另外,名为“”的节点无效。我们在这里需要有效样本数据。如果我们通过删除对命名空间的所有引用来更正您的 xml/查询,那么您的查询就可以正常工作。 db<>fiddle
  • Namespace1 等只是占位符,用于说明涉及命名空间。我在手机上输入这个并试图简短。数据是专有的,所以我无法提供我正在使用的数据。我尝试在查询中删除命名空间引用,但仍然没有记录。我希望了解我的 xPath 语法(或实际的 sql)可能会如何让我失望。
  • 然而,问题在于这意味着我们无法复制您的问题。正如我所说,您的代码与我们所拥有的一样,似乎可以正常工作。
  • 我对帖子进行了一些编辑,以使命名空间更清晰。

标签: sql xml sql-server-2012


【解决方案1】:

这个问题最大的问题是XML本身:

<App xmlns="http://Namespace1">
  <Package xmlns="http://Namespace2">
    <Item>
      <ItemDetails xmlns="http://Namespace3">
        <ItemName>ItemNameValue</ItemName>
      </ItemDetails>
            other_item_stuff
        </Item>
    <Item>
      <ItemDetails>
        <ItemName>ItemNameValue</ItemName>
      </ItemDetails>
    </Item>
        ...
    </Package>
</App>

两大问题:

  • 命名空间都被声明为默认命名空间(它们不包括前缀)。如果没有明确说明,节点内的所有节点 共享相同的默认命名空间。
  • 第一个 &lt;ItemDetails&gt; 位于命名空间 http://Namespace3 中,而第二个 &lt;ItemDetails&gt; 位于命名空间 http://Namespace2 中(继承自 &lt;Package&gt;

这意味着:如果您可以(任何机会)更改 XML 的结构,请先尝试这样做。

如果你必须处理这个问题,你可以尝试这种干净但笨拙的方法。

WITH XMLNAMESPACES(
'http://Namespace1' AS ns1,
'http://www.w3.org/2001/XMLSchema-instance' AS xsi,
'http://Namespace2' AS ns2,
'http://Namespace3' AS ns3)    
SELECT COALESCE(Items.d.value('(ns2:ItemDetails/ns2:ItemName/text())[1]','varchar(200)')
               ,Items.d.value('(ns3:ItemDetails/ns3:ItemName/text())[1]','varchar(200)')) AS ItemName
FROM @xml.nodes('/ns1:App/ns2:Package/ns2:Item') Items(d);

另一种方法是使用命名空间通配符,但要注意名称不明确...

SELECT Items.d.value('(*:ItemDetails/*:ItemName/text())[1]','varchar(200)') AS ItemName
FROM @xml.nodes('/*:App/*:Package/*:Item') Items(d)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 2013-07-14
    • 2017-04-23
    • 1970-01-01
    相关资源
    最近更新 更多