使用 *typed* XML 从父节点读取属性时出现 XQuery 错误(value() 需要单例)

XQuery Error when reading attribute from parentnode with *typed* XML (value() requires a singleton)

我有一个简单的XML:

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

和select以下:

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 无效?

看来您很清楚,这不是必须让解析器相信只有一件事被传递给 value() 的常见问题。如您所见,此问题特定于 typed XML

使用 google 我发现 this ancient blogpost 有希望的文本

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

Most people get by that. The real fun starts when you do examples using untyped XML and XPath expressions with the text() node test. text() works just fine when using untyped XML, but fails against typed XML with simple content

它讨论了 SQL 联机丛书和 SQL Server 2005 XML 最佳实践论文,我 认为 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() 不喜欢给定类型 xml 类型的值,但需要字符串。所以我们给它一个字符串。