Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I preserve all tags, structure and text in an xml document replacing only some with XSLT?

I've been trying to apply a simple xsl style to an xml document:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <html>
      <body>

        <xsl:for-each select="//title">
          <h1><xsl:value-of select="."/></h1>
        </xsl:for-each>

      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Unfortunately, this seems to just simply ignore all other tags and remove them as well as their contents from the output, and I'm only left with titles converted to h1s. What I would like to be able to do is to have my document's structure remain, while replacing only some of its tags.

So that for example if I have this document:

<section>
  <title>Hello world</title>
  <p>Hello!</p>
</section>

I could get this:

<section>
  <h1>Hello world</h1>
  <p>Hello!</p>
</section>

No quite sure where in the XSLT manual to start looking.

like image 893
snitko Avatar asked Jan 31 '26 19:01

snitko


2 Answers

As O. R. Mapper says, the solution to this is to add an identity template to your transform and just override the parts you need to. This would be the complete solution:

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

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

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

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

When run on your sample input, this produces:

<html>
  <body>
    <section>
      <h1>Hello world</h1>
      <p>Hello!</p>
    </section>
  </body>
</html>

If you really just want to preserve your original XML but replace the <title>, you can just remove the middle <xsl:template> and you should get the result:

<section>
  <h1>Hello world</h1>
  <p>Hello!</p>
</section>
like image 160
JLRishe Avatar answered Feb 03 '26 12:02

JLRishe


You want to replace just <title> elements. However, in your XSLT, you define a template for the root element (/) of your document, and you replace the entire root element with the contents of your template.

What you actually want to do is define an identity transform template (google this, it's an important concept in XSLT) to copy basically everything from your source document, and a template that only matches your <title> elements and replaces them with your new code, like this:

<xsl:template match="title">
    <h1><xsl:value-of select="."/></h1>
</xsl:template>
like image 28
O. R. Mapper Avatar answered Feb 03 '26 13:02

O. R. Mapper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!