我正在将一些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#读取数据并将模式应用于作为比较的结果,但我的技能有限,因此没有取得多大成功。
非常感谢!
答案 0 :(得分: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节点是一种更方便的方法;然而,数据的含义和解释不会改变。意义&amp;数据的解释由模式定义,CDATA
只是数据(根据模式解释)。