D-Klotz
D-Klotz

Reputation: 2083

XSLT: Is it possible to blindly pass most elements yet transform specific elements?

Given an xml file that has elements a, b, c and d is it possible to write an XSLT that will alter only element "c" and blindly pass all other elements?

For example:

<?xml version="1.0" encoding="UTF-8"?>
<Person>
    <a>pass me blindly</a>
    <b>pass me blindly</b>
    <c>I need XSLT to convert me</c>
    <d>pass me blindly</d>
</Person>

Is it possible to have an XSLT that does the transform of "c" and yet all of the other elements are passed as they are in the source?

I would end up with:

<?xml version="1.0" encoding="UTF-8"?>
<Person>
    <a>pass me blindly</a>
    <b>pass me blindly</b>
    <c>I've been CONVERTED!</c>
    <d>pass me blindly</d>
</Person>

And yes my knowledge level of XSLT is limited.

Upvotes: 2

Views: 200

Answers (3)

Martin Honnen
Martin Honnen

Reputation: 167716

As you mention Altova you might also be able to use XSLT 3 (if you have a current version of Altova) and in XSLT 3 you can use xsl:mode on-no-match with the different values on-no-match? = "deep-copy" | "shallow-copy" | "deep-skip" | "shallow-skip" | "text-only-copy" | "fail", see https://www.w3.org/TR/xslt-30/#built-in-rule and https://www.w3.org/TR/xslt-30/#declaring-modes, a declaration of

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

would establish the identity transformation as the built-in rules for the unnamed mode. Then you would only need to add a template for that element you want to transform.

Upvotes: 0

Bill Richards
Bill Richards

Reputation: 172

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml-stylesheet type="text/xml" href=".\XSLTFile1.xslt"?>
 <Person >
  <a>pass me blindly</a>
  <b>pass me blindly</b>
  <c>I need XSLT to convert me</c>
  <d>pass me blindly</d>
</Person>

The following XSL Transformation template will give you the desired result

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
  <xsl:template match="xsl:stylesheet" />
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="c">
    <c>I've been CONVERTED!</c>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 3

zx485
zx485

Reputation: 29052

You have two possibilities to achieve what you want:

  • a WhiteList approach and a
  • a BlackList approach

The first one copies all nodes except for the white-listed which are processed differently:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />

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

  <xsl:template match="c">
    <xsl:value-of select="concat('The node ',name(),' is being processed.')" />
  </xsl:template>  

</xsl:stylesheet>

The second one copies only the blacklisted nodes which should not processed further:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />

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

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

  <xsl:template match="*[parent::Person]" priority="0">
    <xsl:value-of select="concat('The node ',name(),' is being processed.')" />
  </xsl:template>   

</xsl:stylesheet>

Upvotes: 1

Related Questions