1

I have an XML document as follows

<Element>
    <Element1>
        <Element2 attr1="Horizontal"/>
    </Element1>
    <Element1 attr1="V"/>
    <Element1>
        <Element2 attr1="Island"/>
    </Element1>
</Element>

I would like to have an XSLT to transform the XML with the following conditions:

  1. If the attr1 value is "Horizontal" or "H", it has to be replaced with "H"
  2. If the attr1 value is "Vertical" or "V", it has to be replaced with "V"
  3. If the attr1 value is "Island" or "ISL", it has to be replaced with "ISL"
  4. Otherwise the same value in attr1 appears as it is

So that the resultant XML appears as follows:

<Element>
    <Element1>
        <Element2 attr1="H"/>
    </Element1>
    <Element1 attr1="V"/>
    <Element1>
        <Element2 attr1="ISL"/>
    </Element1>
</Element>

I have the following XSLT. The or condition does not seem to work here. How can I change it?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="@attr1">
   <xsl:attribute name="attr1">
     <xsl:choose>
      <xsl:when test=". ='Horizontal' or 'H'">
        <xsl:text>H</xsl:text>
      </xsl:when>
      <xsl:when test=". = 'Vertical' or 'V'">
        <xsl:text>V</xsl:text>
      </xsl:when>
     </xsl:choose>
   </xsl:attribute>
</xsl:template>
</xsl:stylesheet>
1
  • 1
    You've described the processing in terms of four rules. XSLT is a rule-based language, so these rules translate directly into XSLT template rules as shown by @kjhughes. But your error is very simple: your test condition means test="boolean(.='Horizontal') or boolean('H')", and boolean('H') is always true, so the test always passes. Commented Oct 5, 2015 at 22:59

2 Answers 2

3

Instead of:

<xsl:when test=". ='Horizontal' or 'H'">

you should be using:

<xsl:when test=". ='Horizontal' or . = 'H'">

Or simply:

<xsl:when test=". ='Horizontal'>

since you don't really want to change "H".

Here's a complete example:

XSLT 1.0

<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"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="@attr1">
    <xsl:attribute name="attr1">
        <xsl:choose>
            <xsl:when test=". = 'Horizontal'">H</xsl:when>
            <xsl:when test=". = 'Vertical'">V</xsl:when>
            <xsl:when test=". = 'Island'">ISL</xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

Comments

3

I would use match patterns to do the conditional processing:

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

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

  <xsl:template match="@attr1[. = 'Horizontal']">
    <xsl:attribute name="attr1">H</xsl:attribute>
  </xsl:template>

  <xsl:template match="@attr1[. = 'Vertical']">
    <xsl:attribute name="attr1">V</xsl:attribute>
  </xsl:template>

  <xsl:template match="@attr1[. = 'Island']">
    <xsl:attribute name="attr1">ISL</xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

Note: overrides of the following form will not work when attribute values are attempted to be set via xsl:copy:

  <xsl:template match="@attr1[. = 'Horizontal']">
    <xsl:copy>H</xsl:copy>
  </xsl:template>

@Abel provided a succinct explanation in an earlier comment, preserved here:

An attribute does not have children, hence xsl:copy will create a copy of the attribute and its contents. You are then adding a text node to the attribute, which is silently ignored: "the content is instantiated only for nodes of types that can have attributes or children (i.e. root nodes and element nodes)." (where 'content' refers to the sequence constructor).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.