从带有* typed * XML的父节点读取属性时,XQuery错误(value()需要单例)

时间:2019-03-27 08:45:00

标签: sql sql-server xml xquery-sql

我有一个简单的XML:

DECLARE @x1 xml = '<r>
    <o a="1">
        <o a="2">
        </o>
    </o>
</r>';

然后选择以下内容:

SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x1.nodes('/r//o') r(o);

一切都很好:

NULL
1

当我使用输入的XML时:

CREATE XML SCHEMA COLLECTION [dbo].test AS '
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="r">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:restriction base="xsd:anyType">
                    <xsd:sequence>
                        <xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
                    </xsd:sequence>
                </xsd:restriction>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
    <xsd:complexType name="o">
        <xsd:complexContent>
            <xsd:restriction base="xsd:anyType">
                <xsd:sequence>
                    <xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
                </xsd:sequence>
                <xsd:attribute name="a" type="xsd:string" />
            </xsd:restriction>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>'
GO

DECLARE @x2 xml(dbo.test) = '<r>
    <o a="1">
        <o a="2">
        </o>
    </o>
</r>';

SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);

我得到了错误:

XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'

为什么无类型的XML可以工作而无类型的XML不能工作?

1 个答案:

答案 0 :(得分:0)

似乎您很了解,这不是说服解析器仅将一件事传递给value()的常见问题。正如您所观察到的,此问题特定于键入的XML

使用Google我发现this ancient blogpost包含有前途的文字

rt是XQuery 1.0 / XPath 2.0数据模型的一部分。

  

大多数人都那样做。当您使用带text()节点测试的无类型XML和XPath表达式进行示例时,真正的乐趣就开始了。当使用无类型XML时,text()可以很好地工作,但是对具有简单内容的类型XML失败

它讨论了SQL Books Online和SQL Server 2005 XML Best Practices论文,我认为this book here。我没有寻找最新的参考资料。但是使用我在那找到的东西,我已经能够解决您的问题:简单替换

SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);

SELECT r.o.value('fn:string(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);

基本上,value()不喜欢被赋予typed-xml-type的值,而是想要字符串。所以我们给它一个字符串。