使用此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 :(得分:1)
您的来源是对XML的可怕滥用!你应该向那些设计并向你提供这种垃圾的人抱怨。
使用单个模板,除了删除或扩展源中已有的元素之外,您无法执行任何操作。
我相信这种转变可以满足您的需求。它的工作原理是复制Country
根元素并处理其内容。第二个模板匹配info
属性为enum
的所有CTRY
元素,这些元素构成了CountryInfo
输出元素的基础。
状态信息必须以递归方式完成,方法是使用call-template
插入来自以下info
元素的信息(如果enum
属性为ST
。< / p>
由于源数据的结构,这种转换非常脆弱,如果有任何意外的元素,它将会中断。请注意。
<?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>
答案 1 :(得分:0)
您正在制作所有州的完整列表,因为在您的<xsl:for-each>
内,您有另一个<xsl:for-each>
选择所有州的“跳起来”到具有/Country/info
的根节点。
在这种情况下,对于每个“国家/地区”元素,您希望找到info
信息@enum='ST' who's nearest preceding
@ enum ='CTRY'的所有element with
元素。产生“状态”。
不是从“拉”式接近它,而是“推送”正确的内容并匹配适用的模式。它将使您的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>
答案 2 :(得分: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>