2016-02-24 58 views
2

我有一個xml數據文件。我也有一個轉換該文件的xslt文件。這是我現在擁有的。原始的XML文件:使用XSLT,當子元素包含無真屬性時移除父元素

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="file:///C:/Users/chvl/Desktop/New%20folder%20(2)/UntitledDS.xslt"?> 
<L4 type="schema" guid="de2f8f94-8db6-4979-b32f-8db4bfac3f3c" versionNumber="16" DpaLength="4"> 
<L4 type="group"> 
    <FirmID type="item"> 
     <value>872</value> 
    </FirmID> 
    <FirmName type="item"> 
     <value>Generic Name Here</value> 
    </FirmName> 
    <FirmRef type="item"> 
     <value>LC</value> 
    </FirmRef> 
    <ReportingEndDate type="item"> 
     <value>2015-05-31</value> 
    </ReportingEndDate> 
    <L4 type="group"> 
     <_x0030_257 type="item"> 
      <value xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
     </_x0030_257> 
     <_x0030_258 type="item"> 
      <value>1791886</value> 
     </_x0030_258> 
     <_x0030_725 type="item"> 
      <value xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
     </_x0030_725> 
     <_x0030_726 type="item"> 
      <value>407897</value> 
     </_x0030_726> 
    </L4> 
</L4> 
</L4> 

這裏是通過XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="file:///C:/Users/chvl/Desktop/New%20folder%20(2)/UntitledDS.xslt"?> 
<Root xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="L4" type="schema" guid="de2f8f94-8db6-4979-b32f-8db4bfac3f3c" versionNumber="16" DpaLength="4"> 
<Main name="L4" type="group"> 
    <FirmID type="item"> 
     <value>872</value> 
    </FirmID> 
    <FirmName type="item"> 
     <value>Generic Name Here</value> 
    </FirmName> 
    <FirmRef type="item"> 
     <value>LC</value> 
    </FirmRef> 
    <ReportingEndDate type="item"> 
     <value>2015-05-31</value> 
    </ReportingEndDate> 
    <Data name="L4" type="group"> 
     <DataItem dpa="_x0030_257"> 
      <value></value> 
     </DataItem> 
     <DataItem dpa="_x0030_258"> 
      <value>1791886</value> 
     </DataItem> 
     <DataItem dpa="_x0030_725"> 
      <value></value> 
     </DataItem> 
     <DataItem dpa="_x0030_726"> 
      <value>407897</value> 
     </DataItem> 
    </Data> 
</Main> 
</Root> 

要在原始XML後的新的XML文件,你看到孩子元素,其中,XSI:無=「真」?那麼,當發生這種情況時,我需要刪除它的父元素。在這個例子中,我需要刪除其所有子元素。

現在,我所嘗試的是將此代碼放在我的XSLT的末尾。

<xsl:template match="/*/*/*/node()[./*/(@xsi:nil = 'true')]|@*">/xsl:template> 

它的工作原理,但它也從我的根元素刪除屬性和以及其他地方。但我需要所有這些屬性。我覺得我離解決這個問題只有一步之遙,但這一步變成了一個巨大的飛躍。

任何幫助,將不勝感激。

這是完整的XSLT和代碼片段代碼,用於刪除nil父元素(上面的示例沒有與代碼段一起運行以刪除nils)。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 


    <xsl:template match="/*"> 
    <Root> 
     <xsl:attribute name="name" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute> 

     <xsl:choose> 
       <xsl:when test="/*[type='schema']"> 
        <xsl:apply-templates select="ignore"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </Root> 
</xsl:template> 

    <xsl:template match="/*/*[@type='group']"> 

    <Main> 
     <xsl:attribute name="name" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute> 

     <xsl:choose> 
       <xsl:when test="child::*[type='item']"> 
        <xsl:apply-templates select="ignore"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </Main> 
</xsl:template> 


    <xsl:template match="/*/*/*[@type='group']"> 
    <Data> 
     <xsl:attribute name="name" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute>  
     <xsl:choose> 
       <xsl:when test="child::*[type='item']"> 
        <xsl:apply-templates select="ignore"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </Data> 
</xsl:template> 

    <xsl:template match="/*/*/*[@type='list']"> 
    <Cube> 
     <xsl:attribute name="name" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute>  
     <xsl:choose> 
       <xsl:when test="child::*[type='item']"> 
        <xsl:apply-templates select="ignore"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </Cube> 
</xsl:template> 

    <xsl:template match="/*/*/Filters[@type='group']"/> 


    <xsl:template match="/*/*/*/*[@type='group']"> 
    <xsl:variable name="count"> 
     <xsl:number/> 
    </xsl:variable> 
    <Data grpcnt="{$count}"> 
     <xsl:attribute name="name" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute>  
     <xsl:choose> 
       <xsl:when test="child::*[type='item']"> 
        <xsl:apply-templates select="ignore"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="@*|node()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </Data> 
</xsl:template> 

    <xsl:template match="*/*/*/*[@type='item']"> 
    <DataItem> 
     <xsl:attribute name="dpa" > 
        <xsl:value-of select="name(.)"/> 
     </xsl:attribute> 
     <value><xsl:value-of select="value"/></value> 
    </DataItem> 
</xsl:template> 

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

    <xsl:template match="/*/*/*/node()[./*/(@xsi:nil = 'true')]|@*"> 

</xsl:template> 



</xsl:stylesheet> 

PS:請記住,元素名稱的變化,這就是爲什麼我使用星星而不是硬編碼標籤名稱。

+0

您的輸入XML有多個根,前綴xsi沒有在xslt – wero

+0

中定義@wero'xsi:'與XSD相關,因爲在這種情況下不需要定義(我沒有仔細查看)。多根問題只是一個格式問題,我現在已經解決了。 –

+0

@MathiasMüller* input * doc格式不正確,需要定義前綴「xsi」,因爲它在xpath位置步驟中使用。無論如何,你已經找到了答案... – wero

回答

2

我認爲僅僅從最後一個模板的模板匹配去除|@*可能會解決這個問題:

<xsl:template match="/*/*/*/node()[./*/(@xsi:nil = 'true')]"> 

它的工作原理,但它也從我的根元素刪除屬性和以及其他地方。

那是因爲你原來的表達:

/*/*/*/node()[./*/(@xsi:nil = 'true')] | @* 

|或「聯合」意味着:要麼一切的|向左或一切的它的權利(因爲只有有一個這樣的符號)。

因此,該表達意味着:具有真實nil屬性的任何屬性的文件中的任意位置的節點。

既然你提到你的問題 「堆積如山」,你的表達:

/*/*/*/node()[./*/(@xsi:nil = 'true')] 

也相當堆積如山。只有使用/*/*/*/如果嵌套層次真的很重要,並且您想在其他地方保留元素與nil="true"

如果嵌套並不重要,你將最終

node()[./*/(@xsi:nil = 'true')] 

然後,node()過於籠統,因爲它爲任何類型的節點,不僅元素節點測試。使用*而不是指元素:

*[./*/(@xsi:nil = 'true')] 

謂詞([...])裏面,有沒有必要開始./,因爲這種情況下被隱含反正假設:

*[*/(@xsi:nil = 'true') 

不需要括號:

*[*/@xsi:nil = 'true'] 

如果xsi:nil屬性只有存在時它的值是「真」,你甚至可以寫

*[*/@xsi:nil] 

一個最後的一番話對此表達:我猜你包括在表達|@*,因爲你也想排除這樣的元素的所有屬性,右?別擔心,有

<xsl:template match="*[*/@xsi:nil]"/> 

將不會處理這些元素的任何屬性或內容。


隨着用戶WERO所指出的,你還需要聲明XSI命名空間中的XSLT樣式表,使其工作:

<xsl:stylesheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 

更一般性的建議:看來,你開始的所有模板匹配從文檔節點,使模式絕對。如果您有意這樣做,那很好,但它也會限制XSLT樣式表的多功能性。

+0

這很好。感謝您的答覆和詳細的解釋。 – LatinCanuck