2013-05-14 81 views
1

使用此XML輸入,我無法將元素添加到特定部分。根據元素屬性類型對XML進行分類

<Country> 
    <info enum="CTRY" name="United Sates of America" total-states="50" /> 
    <info enum="ST" name="New York" population="8,244,910"/> 
    <info enum="ST" name="Chicago" population="2,707,120"/> 
    <info enum="CTRY" name="Germany" total-states="16"/> 
    <info enum="ST" name="Berlin" population="3,469,910"/> 
    <info enum="ST" name="Brandenburg" population="2,500,000"/> 
</Country> 

這裏是我的XSL,

<xsl:template match="/"> 
    <Country> 
    <xsl:for-each select="Country/info"> 
     <xsl:if test="@enum='CTRY'"> 
     <CountryInfo> 
      <name>Country Name: <xsl:value-of select="@name"/></name> 
      <districts><xsl:value-of select="@total-states"></xsl:value-of></districts> 
      <xsl:for-each select="/Country/info"> 
      <xsl:if test="@enum='ST'"> 
       <state> 
       <stateName>State Name: <xsl:value-of select="@name"/></stateName> 
       <statePop>State Population: <xsl:value-of select="@population"/></statePop> 
       </state> 
      </xsl:if> 
      </xsl:for-each> 
     </CountryInfo> 
     </xsl:if> 
    </xsl:for-each> 
    </Country> 
</xsl:template> 

的問題是,所有的狀態都顯示出來了這兩個國家。

這裏是我想生成XML輸出,

<Country> 
    <CountryInfo> 
    <name>Country Name: United Sates of America</name> 
    <districts>50</districts> 
    <state> 
     <stateName>State Name: New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
    </state> 
    <state> 
     <stateName>State Name: Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
    </state> 
    </CountryInfo> 
    <CountryInfo> 
    <name>Country Name: Germany</name> 
    <districts>16</districts> 
    <state> 
     <stateName>State Name: Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
    </state> 
    <state> 
     <stateName>State Name: Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
    </state> 
    </CountryInfo> 
</Country> 

是否有可能使用XSLT來做到這一點?

+0

如果你展示了你的樣式表,它會有所幫助。您在文章中的所有內容都是單個模板。 – Borodin

回答

1

您的源代碼是XML的可怕濫用!你應該抱怨任何設計和提供這種垃圾的人。

對於單個模板,除了已經在源代碼中的元素之外,您無法進行任何操作。

我相信這個轉換可以滿足你的需求。它的工作原理是複製Country根元素並處理其內容。第二個模板匹配enum屬性爲CTRY的所有info元素,這些元素構成CountryInfo輸出元素的基礎。

狀態信息必須被完成遞歸,通過使用call-template插入從以下info元素中的信息,如果它具有一個ST屬性enum

由於源數據的結構,這種轉換是非常脆弱的,並且如果有任何意外的元素將會中斷。請小心。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:strip-space elements="*"/> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/Country"> 
    <xsl:copy> 
     <xsl:apply-templates select="*"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="info[@enum='CTRY']"> 
    <CountryInfo> 
     <name> 
     <xsl:text>Country name: </xsl:text> 
     <xsl:value-of select="@name"/> 
     </name> 
     <districts> 
     <xsl:value-of select="@total-states"/> 
     </districts> 
     <xsl:call-template name="state"/> 
    </CountryInfo> 
    </xsl:template> 

    <xsl:template name="state"> 
    <xsl:param name="i" select="1"/> 
    <xsl:if test="following-sibling::info[$i][@enum='ST']"> 
     <state> 
     <stateName> 
      <xsl:text>State Name: </xsl:text> 
      <xsl:value-of select="following-sibling::info[$i]/@name"/> 
     </stateName> 
     <statePop> 
      <xsl:text>State Population: </xsl:text> 
      <xsl:value-of select="following-sibling::info[$i]/@population"/> 
     </statePop> 
     </state> 
     <xsl:call-template name="state"> 
     <xsl:with-param name="i" select="$i+1"/> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

輸出

<?xml version="1.0" encoding="utf-8"?> 
<Country> 
    <CountryInfo> 
     <name>Country name: United States of America</name> 
     <districts>50</districts> 
     <state> 
     <stateName>State Name: New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name: Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
     </state> 
    </CountryInfo> 
    <CountryInfo> 
     <name>Country name: Germany</name> 
     <districts>16</districts> 
     <state> 
     <stateName>State Name: Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name: Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
     </state> 
    </CountryInfo> 
</Country> 
0

你正在生產的所有狀態的完整列表,因爲裏面你<xsl:for-each>你所說的「跳起來」到了另一個<xsl:for-each>這是選擇的國家的所有根節點爲/Country/info

在這種情況下,對於每一個「國家」的元素,你要找到所有的info元素與@enum='ST' who's nearest preceding信息element with @枚舉='CTRY'`是當前一個以生產‘狀態’。

而不是從「拉」風格接近它,看起來「推」正確的內容,並匹配適用的模式。這將使您的XSLT更容易生成並幫助模塊化成更容易維護的獨特模板(並且在進行導入時更容易覆蓋)。

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

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

    <xsl:template match="Country"> 
    <xsl:copy> 
     <xsl:apply-templates select="info[@enum='CTRY']"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="info[@enum='CTRY']"> 
     <CountryInfo> 
      <name><xsl:value-of select="@name"/></name> 
      <districts><xsl:value-of select="@total-states"/></districts> 
      <xsl:apply-templates 
         select="following-sibling::info[@enum='ST'] 
            [generate-id(
             preceding-sibling::info[@enum='CTRY'][1]) 
            = generate-id(current())]"/> 
     </CountryInfo> 
    </xsl:template> 

    <xsl:template match="info[@enum='ST']"> 
     <state> 
      <stateName> 
       <xsl:text>State Name: </xsl:text> 
       <xsl:value-of select="@name"/> 
      </stateName> 
      <statePop> 
       <xsl:text>State Population: </xsl:text> 
       <xsl:value-of select="@population"/> 
      </statePop> 
     </state> 
    </xsl:template> 

</xsl:stylesheet> 
0

這個簡短和簡單的變換

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kStates" match="info[@enum='ST']" 
      use="generate-id(preceding-sibling::info[@enum='CTRY'][1])"/> 

<xsl:template match="/*"> 
    <Country> 
    <xsl:apply-templates select="info[@enum='CTRY']"/> 
    </Country> 
</xsl:template> 

<xsl:template match="info[@enum='CTRY']"> 
    <CountryInfo> 
    <name>Country Name: <xsl:value-of select="@name"/></name> 
    <districts><xsl:value-of select="@total-states"/></districts> 
    <xsl:apply-templates select="key('kStates', generate-id())"/> 
    </CountryInfo> 
</xsl:template> 

<xsl:template match="info[@enum='ST']"> 
    <state> 
    <stateName>State Name:<xsl:value-of select="@name"/></stateName> 
    <statePop>State Population: <xsl:value-of select="@population"/></statePop> 
    </state> 
</xsl:template> 
</xsl:stylesheet> 

當所提供的XML文檔(在所有不可怕:))施加:

<Country> 
    <info enum="CTRY" name="United Sates of America" total-states="50" /> 
    <info enum="ST" name="New York" population="8,244,910"/> 
    <info enum="ST" name="Chicago" population="2,707,120"/> 
    <info enum="CTRY" name="Germany" total-states="16"/> 
    <info enum="ST" name="Berlin" population="3,469,910"/> 
    <info enum="ST" name="Brandenburg" population="2,500,000"/> 
</Country> 

產生想要的,正確的結果:

<Country> 
    <CountryInfo> 
     <name>Country Name: United Sates of America</name> 
     <districts>50</districts> 
     <state> 
     <stateName>State Name:New York</stateName> 
     <statePop>State Population: 8,244,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name:Chicago</stateName> 
     <statePop>State Population: 2,707,120</statePop> 
     </state> 
    </CountryInfo> 
    <CountryInfo> 
     <name>Country Name: Germany</name> 
     <districts>16</districts> 
     <state> 
     <stateName>State Name:Berlin</stateName> 
     <statePop>State Population: 3,469,910</statePop> 
     </state> 
     <state> 
     <stateName>State Name:Brandenburg</stateName> 
     <statePop>State Population: 2,500,000</statePop> 
     </state> 
    </CountryInfo> 
</Country> 
相關問題