2013-07-24 69 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