简体   繁体   中英

How to call template from another template in XSLT?

I have the following xml:

<rootelement>
   <parentelement>
      <mytype>123</mytype>
      <myvalue>abc</myvalue>
   </parentelement>
   <parentelement>
      <mytype>234</mytype>
      <myvalue>xyz</myvalue>
   </parentelement>
</rootelement>

First I apply template that uses dictionary to change values of mytype:

   <parentelement>
      <mytype>Mapped1</mytype>
      <myvalue>abc</myvalue>
   </parentelement>
   <parentelement>
      <myvalue>qwe</myvalue>
   </parentelement>

I want to apply next transform that removes the whole parentelement if mytype tag was removed. In other words I want the second transform to create the following XML:

   <parentelement>
      <mytype>Mapped1</mytype>
      <myvalue>abc</myvalue>
   </parentelement>

I've tried adding at the end of the first template the following:

<xsl:template match="mytype">
    ...
    <xsl:call-template name="mytypetemplate"/>
</xsl:template>

With the following template as the second one:

<xsl:template name="mytypetemplate" match="/rootelement/parentelement[not(mytype) or mytype[not(node())]]"/>

But the result I got is that it executes the first template, but not the second one. In other words, it removes mytype (first template) but it does not remove the whole parentelement for element without mytype (second template). How can I apply the second transform after the first one?

Thanks!

You can separate processing steps using mode s ( https://www.w3.org/TR/xslt/#element-mode ) and use variables to store and use temporary results, in the example

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

    <xsl:mode on-no-match="shallow-copy"/>
    <xsl:mode name="step1" on-no-match="shallow-copy"/>

    <xsl:variable name="step1-result">
        <xsl:apply-templates mode="step1"/>
    </xsl:variable>

    <xsl:template match="parentelement[myvalue = 'abc']/mytype" mode="step1"/>

    <xsl:template match="/">
        <xsl:apply-templates select="$step1-result/node()"/>
    </xsl:template>

    <xsl:template match="parentelement[not(mytype)]"/>

</xsl:stylesheet>

the mode step1 removes the mytype element from parentelement s with myvalue being abc and the default mode processes the temporary result created in the variable step1-result to eliminate any parentelement s not having a mytype child.

So for the input

<?xml version="1.0" encoding="UTF-8"?>
<rootelement>
    <parentelement>
        <mytype>123</mytype>
        <myvalue>abc</myvalue>
    </parentelement>
    <parentelement>
        <mytype>234</mytype>
        <myvalue>xyz</myvalue>
    </parentelement>
</rootelement>

then result is

<rootelement>

        <parentelement>
                <mytype>234</mytype>
                <myvalue>xyz</myvalue>
        </parentelement>
</rootelement>

Online at http://xsltfiddle.liberty-development.net/b4GWV2 .

A slight variant is

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>
  <xsl:mode name="step1" on-no-match="shallow-copy"/>

  <xsl:template match="parentelement[myvalue = 'abc']/mytype" mode="step1"/>

  <xsl:template match="/">
    <xsl:variable name="step1-result">
      <xsl:apply-templates mode="step1"/>
    </xsl:variable>
    <xsl:apply-templates select="$step1-result/node()"/>
  </xsl:template>

  <xsl:template match="parentelement[not(mytype)]"/>

</xsl:stylesheet>

you can see that online at http://xsltfiddle.liberty-development.net/b4GWV2/1 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM