deuri
deuri

Reputation: 25

XSLT templates for creating missing elements confict with each other

I use XSLT transformation to add elements configuration and status to my XML data in case one or both of them are missing. I'd like to use independent templates to handle each of the these, but it seems only one of the template takes effect.

Source data:

<data>
  <environment>
    <id>test</id>
    <details>Detail info for environment...</details>
  </environment>
  <default_conf>abcd1234</default_conf>
  <default_status>1</default_status>
</data>

XSLT:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />
    <!-- identity transformation -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
 <!-- if configuration not given, create it with the value of default_conf -->
 <xsl:template match="data[not(configuration)]">
   <xsl:copy>
     <xsl:apply-templates/>
        <!--xsl:apply-templates select="@*|node()"/-->
       <configuration><xsl:value-of select="default_conf"/></configuration>
   </xsl:copy>
 </xsl:template>
 <!-- if status not given, create it with the value of default_status -->
 <xsl:template match="data[not(status)]">
   <xsl:copy>
     <xsl:apply-templates/>
     <!--xsl:apply-templates select="@*|node()"/-->
     <status><xsl:value-of select="default_status"/></status>
   </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

In the result XML only the element is created, but not the element. What's wrong with the transformation templates and how to correct it?

Please note that I need to pass also the default_conf and default status elements, so I'm not looking to rename these elements.

Desired output:

<data>
  <environment>
    <id>test</id>
    <details>Detail info for environment...</details>
  </environment>
  <default_conf>abcd1234</default_conf>
  <default_status>1</default_status>
  <configuration>abcd1234</configuration>
  <status>1</status>
</data>

Upvotes: 1

Views: 125

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117043

In XSLT,

A node is processed by finding all the template rules with patterns that match the node, and choosing the best amongst them;
https://www.w3.org/TR/1999/REC-xslt-19991116/#section-Processing-Model

When both configuration and status are missing, you have two templates that match the same node, with the same priority. This is an error:

An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matching template rules that are left, the one that occurs last in the stylesheet.
https://www.w3.org/TR/1999/REC-xslt-19991116/#conflict

The simple solution is to use a single template with two xsl:if instructions to add each missing node. Otherwise you would need to use not two, but three templates - and make sure the added template takes precedence.

Upvotes: 1

Related Questions