2014-06-18 69 views
2

我收到一個大的XML文件,並且XML文件通常不會驗證爲模式文件。 我不想刪除整個xml文件,而是刪除「無效」內容並保存其餘的XML文件。xmllint驗證後刪除無效的XML

我使用xmllint驗證該命令的XML:

xmllint -schema testSchedule.xsd testXML.xml 

XSD文件(在本例中名爲testSchedule.xsd):

<?xml version="1.0" encoding="utf-8"?> 
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.testing.dk" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="MasterData"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element name="Items"> 
      <xs:complexType> 
      <xs:sequence> 
       <xs:element name="Item" maxOccurs="unbounded" minOccurs="0"> 
       <xs:complexType> 
        <xs:sequence> 
        <xs:element type="xs:integer" name="Id" minOccurs="1"/> 
        <xs:element type="xs:integer" name="Width" minOccurs="1"/> 
        <xs:element type="xs:integer" name="Height" minOccurs="0"/> 
        <xs:element type="xs:string" name="Remark"/> 
        </xs:sequence> 
       </xs:complexType> 
       </xs:element> 
      </xs:sequence> 
      </xs:complexType> 
     </xs:element> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 

和XML文件(在這個例子名爲testXML.xml):

<?xml version="1.0" encoding="ISO-8859-1" ?> 
<MasterData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.testing.dk"> 
    <Items> 
     <Item> 
      <Id>1</Id> 
      <Width>10</Width> 
      <Height>100</Height> 
      <Remark>This is OK</Remark> 
     </Item> 
     <Item> 
      <Id>2</Id> 
      <Width>20</Width> 
      <Height>200</Height> 
      <Remark>This is OK - But is missing Height a non mandatory field</Remark> 
     </Item> 
     <Item> 
      <Id>3</Id> 
      <Height>300</Height> 
      <Remark>This is NOT OK - Missing the mandatory Width</Remark> 
     </Item> 
     <Item> 
      <Id>4</Id> 
      <Width>TheIsAString</Width> 
      <Height>200</Height> 
      <Remark>This is NOT OK - Width is not an integer but a string</Remark> 
     </Item> 
     <Item> 
      <Id>5</Id> 
      <Width>50</Width> 
      <Height>500</Height> 
      <Remark>This is OK and the last</Remark> 
     </Item> 
    </Items> 
</MasterData> 

然後我得到的xmllint命令的結果如下:

testXML.xml:18: element Height: Schemas validity error : Element '{http://www.testing.dk}Height': This element is not expected. Expected is ({http://www.testing.dk}Width). 
testXML.xml:23: element Width: Schemas validity error : Element '{http://www.testing.dk}Width': 'TheIsAString' is not a valid value of the atomic type 'xs:integer'. 
testXML.xml fails to validate 

而這一切都正確 - XML文件中有兩個錯誤。

現在我想有某種形式的工具來刪除條目3和4,所以我結束了這樣的結果:

<?xml version="1.0" encoding="ISO-8859-1" ?> 
<MasterData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.testing.dk"> 
    <Items> 
     <Item> 
      <Id>1</Id> 
      <Width>10</Width> 
      <Height>100</Height> 
      <Remark>This is OK</Remark> 
     </Item> 
     <Item> 
      <Id>2</Id> 
      <Width>20</Width> 
      <Height>200</Height> 
      <Remark>This is OK - But is missing Height a non mandatory field</Remark> 
     </Item> 
     <Item> 
      <Id>5</Id> 
      <Width>50</Width> 
      <Height>500</Height> 
      <Remark>This is OK and the last</Remark> 
     </Item> 
    </Items> 
</MasterData> 

在這裏沒有任何人有一個工具,可以做到這一點? 我目前使用bash腳本和xmllint。 我真的希望有人可以幫忙。

+0

您可以使用XSLT。 XSLT允許您轉換格式良好的XML文檔(即使無效)。爲你的問題添加一個XSLT標籤,你應該得到一些建議。 – helderdarocha

回答

0

使用命令行工具(如xsltproclibxslt))或Saxon(瀏覽器或在線工具),可以使用此XSLT樣式表實現該操作,該樣式表可以在任何支持XSLT 1.0(大多數語言)的環境中運行。這是一個例子。

如果你給你的原始XML文件作爲輸入到XSLT轉換器具有以下樣式表會產生你已經在你的第二個XML所示的結果:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
    xmlns:t="http://www.testing.dk"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="t:Item[t:Id  and not(number(t:Id))]"/> 
    <xsl:template match="t:Item[t:Width and not(number(t:Width))]"/> 
    <xsl:template match="t:Item[t:Height and not(number(t:Height))]"/> 
    <xsl:template match="t:Item[not(t:Width)]"/> 
    <xsl:template match="t:Item[not(t:Id)]"/> 
    <xsl:template match="t:Item[not(t:Remark)]"/> 

</xsl:stylesheet> 

第一<xsl:template>塊簡單的拷貝從所有節點源樹到結果樹。它的優先級低於按名稱匹配節點的特定模板。

由於匹配是在需要符合命名空間限定的選擇器的XPath中完成的,因此您的默認名稱空間在<xsl:stylesheet>開始標記中聲明並映射到用於限定標記名稱的前綴。

每個模板都使用XPath表達式來測試Item中是否存在特定子元素,或者如果該子元素是數字(根據XSD),那麼該子元素是否存在。

我正在使用XSLT 1.0,它受到更廣泛的支持,應該更容易在您的環境中找到。但是,如果您可以使用XSLT 2.0處理器,則可以使用XSLT 2.0功能(如支持XSD類型),而不是將您的值與數字類型進行比較,您可以將它們與特定類型(如xsd:integer)進行比較。

您可以驗證該樣式表在這個XSLT Fiddle中對示例XML執行的轉換。

如果你創建一個包含上面的代碼中的XML文檔,並將其放置在一個文件名爲stylesheet.xsl可以運行使用xsltproc轉型(這可能已存在於環境)使用:

xsltproc stylesheet.xsl testXML.xml > fixedXML.xml 
+0

感謝您的好幫助和快速幫助。 所述文件是具有相當少量數據和錯誤的測試文件。我收到的XML文件是巨大的!並且模式超過3000行。正如我所看到的那樣,XSLT解決方案可以處理衆所周知的錯誤,但是每次都會收到很多不同的驗證錯誤 - 這是由於數據損壞 - 所以我在使用XSLT處理此問題方面遇到了很大的困難。 – user3752427

+0

其實我發佈了一個簡單的XSLT 1.0兼容示例,因爲您可以輕鬆地在您的環境中找到它。但是你可能仍然會考慮XSLT 2.0,因爲你的任務是*轉換* XML文檔。 XSLT 2.0具有架構感知功能,可以自動處理比我在此顯示的更多的功能。見http://www.ibm.com/developerworks/library/x-schemaxslt/。添加XSLT標籤或詢問一個提出這些要求的XSLT 2.0解決方案的新問題。你應該得到一些你可能會用到的有趣的解決方案。 – helderdarocha