2013-05-14 62 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> 
相关问题