user5479362
user5479362

Reputation:

Double usage of <xsl:apply-templates select="@* | node()"/> in transform

I have a transform which is (simplified version) something like that:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/>

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

     <xsl:template match="head">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:text>Transformed document</xsl:text>
            </xsl:element>
        </xsl:element>
     </xsl:template>

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

</xsl:stylesheet> 

It transforms sample HTML document

<?xml version="1.0" encoding="iso-8859-1"?>
<html xml:lang="en" lang="en">
    <head>
        <title>Sample page</title>
        <link rel="stylesheet" href="/style.css" type="text/css"/>
        <meta name="author" content="John Doe"></meta>
    </head>
    <body>
        <h1>Header</h1>
        <p>Some text</p>
        <p>Some other text</p>
    </body>
</html>

To:

<?xml version="1.0" encoding="UTF-8"?><html lang="en" xml:lang="en">
    <head><title>Transformed document</title></head>
    <body>
        <h1>Header</h1>
        <p>Some text</p>
        <p>Some other text</p>
    </body>
</html>

I can't understand why I need to call apply-templates twice. As I understand, the first one should copy everything to the output (including head, which should be overwritten), and the second one should copy only body (which is what I want). However, both seem to be necessary. If I remove that from body, I have only head in output, if I remove first one, I get only extracted text from nodes, not the nodes.

Why in the following example is <xsl:apply-templates select="@* | node()"/> needed twice and is it possible to simplify that example?

Upvotes: 0

Views: 178

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117140

The problem here is not calling xsl:apply-templatestwice, but having an entire template that's redundant.

Since you're not changing body in any way, you can leave it to be processed by the identity transform template (your first template), and remove the last template:

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

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/>

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

     <xsl:template match="head">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:text>Transformed document</xsl:text>
            </xsl:element>
        </xsl:element>
     </xsl:template>

</xsl:stylesheet> 

BTW, you can also simplify the template matching head to:

<xsl:template match="head">
    <head>
        <title>Transformed document</title>
    </head>
</xsl:template>

No need to use xsl:element when the name of the element is known in advance.

Upvotes: 1

Related Questions