1

我正在将一些 XML 文件导入到 SQL 中,这些文件具有我正在验证的 XSD 架构。我发现的“问题”是文件中的某些数据包含在 CDATA 标记中,但相应的 XML 元素被定义为 xsd:token (来自 W3Schools -“令牌数据类型也包含字符,但 XML处理器将删除换行符、回车符、制表符、前导和尾随空格以及多个空格。”)。我注意到的是,当我在 SQL 中针对 Typed XML 变量运行一个简单的 XQuery 时,它正在应用 xsd:token 规则来删除 CDATA 值中的多个空格。在我回到文件的供应商之前,我只是想仔细检查一下正确的结果应该是什么。请参阅下面的代码片段...

CREATE XML SCHEMA COLLECTION dbo.MyTestSchema

AS

N'
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="ROOT">
    <xsd:complexType>
      <xsd:complexContent>
        <xsd:restriction base="xsd:anyType">
          <xsd:sequence>
            <xsd:element ref="Test" 
              minOccurs="0" maxOccurs="unbounded"/>
          </xsd:sequence>
        </xsd:restriction>
      </xsd:complexContent>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="Test" type="TestType"/>
  <xsd:simpleType name="TestType">
    <xsd:restriction base="xsd:token">
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>'

GO

DECLARE @XMLData varchar(MAX) = 
'<ROOT>
  <Test><![CDATA[0spaces]]></Test>
  <Test><![CDATA[1 space]]></Test>
  <Test><![CDATA[2  spaces]]></Test>
  <Test><![CDATA[3   spaces]]></Test>
</ROOT>'

DECLARE @XML xml = @XMLData
DECLARE @MyTestXML xml(CONTENT dbo.MyTestSchema) = @XMLData

;WITH WithoutSchema AS
(
    SELECT [Test] = NULLIF(T2.n.value('.', 'varchar(10)'), '')
    FROM @XML.nodes('/ROOT') AS T1(n)
    CROSS APPLY T1.n.nodes('Test') AS T2(n)
),
WithSchema AS
(
    SELECT [Test] = NULLIF(T2.n.value('.', 'varchar(10)'), '')
    FROM @MyTestXML.nodes('/ROOT') AS T1(n)
    CROSS APPLY T1.n.nodes('Test') AS T2(n)
)
SELECT [WithoutSchema] = N.Test, [WithSchema] = Y.Test
FROM WithoutSchema N
INNER JOIN WithSchema Y
    ON REPLACE(N.Test, ' ', '') = REPLACE(Y.Test, ' ', '')

GO

DROP XML SCHEMA COLLECTION dbo.MyTestSchema

GO

……结果……

WithoutSchema WithSchema
------------- ----------
0spaces       0spaces
1 space       1 space
2  spaces     2 spaces
3   spaces    3 spaces

...如您所见,使用非类型化 xml 变量会保留 CDATA 文本中的空格,但使用类型化变量(使用 xsd:token)会将它们剥离。如果发生这种情况,我认为 xsd 仅适用于非 CDATA 值?这些空格在我们正在加载的数据中具有意义,因此如果这是正确的行为,我需要向供应商提出。我尝试通过 C# 读取数据并将模式应用于作为比较给出的结果,但我的技能有限,因此没有太大的成功。

非常感谢!

4

1 回答 1

1

这似乎是正确的。首先,XML 只是原始数据。你选择原始数据,你得到原始数据。您的数据包含空格,您会得到空格。在第二个中,您将数据声明为显式规范化数据的类型 - 这就是xsd:token类型的含义(空格被折叠,前导和尾随空格被删除)。

xsd:token类型类似于大多数编程语言中的符号声明。在类型和名称之间或名称和赋值之间放置多少空格通常并不重要,例如在 Java/C/C++ 中,这都是有效的:

int         a = 5; // variable is called 'a' not '        a'.
int b
= 5; // not very readable, but the variable is called 'b'.

至于CDATA:CDATA只是指示 XML 解析器将字符视为原始数据的一种方式——但任何其他信息/指令仍然适用。因此,将字符插入 XML 节点是一种更方便的<方式&;但是,数据的含义和因此的解释不会改变。数据的含义和解释由模式定义,并且CDATA是唯一的数据(根据模式解释)。

于 2013-07-24T11:24:52.560 回答