模板内的调用模板

时间:2015-12-30 23:57:34

标签: xml xslt

我有xml文件:

<root>
  <directors>
    <director>
      <name></name>
      <country></country>
    </director>
    (...)
    <director>
      <name></name>
      <country></country>
    </director>
  </directors>
  <movies>
    <movie>
      <country><country>
    </movie>
    (...)
    <movie>
      <country></country>
    </movie>
  </movies>
</root>

在我的XSL转换中,我想创建包含按国家/地区分组的moviedirector元素的XML文件。我设法提取每个不同的国家:

    <xsl:template name="countries"> 
      <xsl:for-each 
        select="distinct-values(/root/directors/director/country | /root/movies/movie/country)">
        <xsl:element name="country">
          <xsl:element name="name">
            <xsl:value-of select="." />
          </xsl:element>
        </xsl:element>
      </xsl:for-each>
    </<xsl:template>

我现在要做的是在<movies>内创建元素<directors><country>,其中包含子元素与父国匹配的元素:

<country>
  <name>UK</name>
  <movies> [movies having element country="UK"] </movies>
  <directors> [as above] </directors>
</country>

我试图使用当前国家/地区名称作为模板内的参数调用模板,但它不起作用。

    <xsl:template name="countries"> 
      <xsl:for-each 
        select="distinct-values(/root/directors/director/country | /root/movies/movie/country)">
        <xsl:element name="country">
          <xsl:element name="name">
            <xsl:value-of select="." />
          </xsl:element>
          <xsl:element name="movies">
            <xsl:call-template name="movie">
              <xsl:with-param name="country" />
            </xsl:call-template>
          </xsl:element>
        </xsl:element>
      </xsl:for-each>
    </<xsl:template>

    <xsl:template name="movie">
      <xsl:param name="country" />
      <xsl:for-each select="/root/movies/movie">
        <xsl:if test="country=$country">
          <!--TODO-->
        </xsl:if>
      </xsl:for-each>
    </xsl:template>

看看我的“解决方案”的复杂程度,我假设我试图以错误的方式做到这一点。如何获取<country>循环迭代指定的for-each元素的元素?我想分别为电影和导演做这件事。

3 个答案:

答案 0 :(得分:1)

至少,您需要为模板参数赋值:

<xsl:call-template name="movie">
    <xsl:with-param name="country" select="." />
</xsl:call-template>

或者,您可以使用XPath谓词表达式来获取movie个孩子等于当前country次迭代的country的{​​{1}}元素:

xsl:for-each

答案 1 :(得分:1)

您可以使用xsl:for-each-group进行分组,而不是使用参数调用模板。 (我想如果distinct-values()对你有用,你必须使用XSLT 2.0。)

XML输入(添加了一些用于测试的值)

<root>
    <directors>
        <director>
            <name>Mr. A</name>
            <country>UK</country>
        </director>
        <director>
            <name>Mrs. B</name>
            <country>US</country>
        </director>
    </directors>
    <movies>
        <movie>
            <country>US</country>
        </movie>
        <movie>
            <country>UK</country>
        </movie>
    </movies>
</root>

XSLT 2.0

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

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

  <xsl:template match="/root">
    <xsl:copy>
      <xsl:for-each-group select="*/director|*/movie" group-by="country">
        <country>
          <name><xsl:value-of select="current-grouping-key()"/></name>
          <directors>
            <xsl:apply-templates select="current-group()[self::director]"/>
          </directors>
          <movies>
            <xsl:apply-templates select="current-group()[self::movie]"/>
          </movies>
        </country>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

XML输出

<root>
   <country>
      <name>UK</name>
      <directors>
         <director>
            <name>Mr. A</name>
            <country>UK</country>
         </director>
      </directors>
      <movies>
         <movie>
            <country>UK</country>
         </movie>
      </movies>
   </country>
   <country>
      <name>US</name>
      <directors>
         <director>
            <name>Mrs. B</name>
            <country>US</country>
         </director>
      </directors>
      <movies>
         <movie>
            <country>US</country>
         </movie>
      </movies>
   </country>
</root>

Working Example

这应该很容易扩展。例如,如果您要从countrydirector中删除movie元素,则只需添加一个模板(<xsl:template match="country"/>)。

答案 2 :(得分:0)

这是一个纯XSLT 1.0解决方案(也可以使用XSLT 2.0处理器正确运行),这是迄今为止最短的。它也与使用$('.go-btn').click(function() { window.location = $('#my-dropdown').val(); });

的XSLT 2.0解决方案一样高效
<xsl:for-each-group>

请注意其他成就:如果某个国家/地区没有任何导演或任何电影,则不会生成空的<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="kCountryByVal" match="country" use="."/> <xsl:key name="kDirMovieByCountry" match="director|movie" use="concat(country, name())"/> <xsl:template match="country[generate-id() = generate-id(key('kCountryByVal',.)[1])]"> <xsl:copy> <name><xsl:value-of select="."/></name> <xsl:apply-templates select="key('kDirMovieByCountry',concat(.,'director'))[1] | key('kDirMovieByCountry',concat(.,'movie'))[1]" mode="do"/> </xsl:copy> </xsl:template> <xsl:template match="director|movie" mode="do"> <xsl:element name="{name()}s"> <xsl:copy-of select="key('kDirMovieByCountry',concat(country,name()))"/> </xsl:element> </xsl:template> <xsl:template match="text()"/> </xsl:stylesheet> <directors/>元素。

将此转换应用于以下XML文档

<movies/>

产生了想要的正确结果

<root>
    <directors>
        <director>
            <name>James Cameron</name>
            <country>CA</country>
        </director>
        <director>
            <name>Steven Spielberg</name>
            <country>US</country>
        </director>
    </directors>
    <movies>
        <movie>
            <name>Titanic</name>
            <country>US</country>
        </movie>
        <movie>
            <name>E.T. the Extra-Terrestrial</name>
            <country>US</country>
        </movie>
    </movies>
</root>

关键概念

  1. <强> Muenchian grouping

  2. 复合 keys 联盟 pattern

  3. XSLT处理模型, templates built-in templates modes

  4. <country> <name>CA</name> <directors> <director> <name>James Cameron</name> <country>CA</country> </director> </directors> </country> <country> <name>US</name> <directors> <director> <name>Steven Spielberg</name> <country>US</country> </director> </directors> <movies> <movie> <name>Titanic</name> <country>US</country> </movie> <movie> <name>E.T. the Extra-Terrestrial</name> <country>US</country> </movie> </movies> </country> 指令,“推送 -style”,多态,避免<xsl:apply-templates>

  5. {li>

    AVT <xsl:call-templates>