1

使用此 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 完成此任务?

4

3 回答 3

1

您的来源是对 XML 的严重滥用!你应该向设计和向你提供这种垃圾的人痛骂。

使用单个模板,您只能删除或扩展源中已有的元素。

我相信这种转换可以满足您的需求。它通过复制Country根元素并处理其内容来工作。第二个模板匹配所有info具有enum属性的元素,这些元素CTRY构成了CountryInfo输出元素的基础。

状态信息必须递归完成,如果它的属性为 ,则使用call-template插入来自后续元素的信息。infoenumST

由于源数据的结构,这种转换非常脆弱,如果有任何意外元素就会中断。请注意。

<?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>
于 2013-05-15T00:17:15.447 回答
0

您正在生成所有状态的完整列表,因为在您的内部<xsl:for-each>有另一个通过“跳转”到根节点来<xsl:for-each>选择所有/Country/info状态。

在这种情况下,对于每个“国家”元素,您要查找所有info带有@enum='ST' who's nearest precedinginfo element with@enum='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>
于 2013-05-15T00:29:49.473 回答
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>
于 2013-05-15T03:58:01.153 回答