2013-07-24 39 views
1

我正在导入一些XML文件到SQL中,该文件有一个我正在验证的XSD模式。我发现的“问题”是文件中的一些数据包含在CDATA标记中,但相应的XML元素被定义为xsd:token(来自W3Schools--“令牌数据类型也包含字符,但XML处理器将删除换行符,回车符,制表符,前导空格和尾随空格以及多个空格。“)。我注意到,当我在SQL中对一个Typed XML变量运行一个简单的XQuery时,它应用了将多个空格移除到CDATA值的xsd:token规则。在我回到文件供应商之前,我只是想仔细检查一下正确的结果应该是什么。请参见下面的代码片段...XML解析器应该将XSD Schema限制应用于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#读取数据并将该模式​​应用于作为比较的结果,但我的技能有限,因此没有太多成功。

非常感谢!

回答

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'. 

至于CDATACDATA只是一种方式指示XML解析器将字符视为原始数据 - 但任何其他信息/说明仍然适用。因此,将字符<&插入XML节点是更方便的方法;然而,数据的含义和解释并没有改变。数据解释的含义由模式定义,CDATA仅为数据(根据模式解释)。

+0

感谢您的回复。我将回到我们的供应商,因为我们收到另一个文件(csv),其中列出了“主键”值,我们应该将该文件加入到相关字段中的XML文件中。麻烦的是,在某些情况下,csv文件包含双空格,然后它没有链接到由xml文件加载的值(应用了它们的模式),这已将其转换为仅1空间,所以现在我们得到孤立的数据:) – user2614273