Pratik
Pratik

Reputation: 211

XSLT create element if doesn't exist?

I am trying to find a way to add an element to input xml file via XSLT only if it doesn't already exist. My solution below works in cases where the element doesn't exist, however if it DOES exist (I still need to put the value for sessionId), it still creates a new one.

XSL:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xsl exsl xs">
    <xsl:output method="xml" version="1.0" indent="yes" encoding="utf-8" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//*[local-name() = 'SessionHeader']">
        <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
            <xsl:choose>
                <xsl:when test="not(sessionId)">
                    <sessionId><xsl:value-of select="9876543210"/></sessionId>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy><xsl:value-of select="9876543210"/></xsl:copy>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Sample XML:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Header>
    <SessionHeader>
      <sessionId />
    </SessionHeader>
  </soap:Header>
  <soap:Body>
      ....
  </soap:Body>
</soap:Envelope>

After XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soap:Header>
      <SessionHeader>
         <sessionId />
         <sessionId xmlns="">9876543210</sessionId>
      </SessionHeader>
   </soap:Header>
   <soap:Body>
       ....
   </soap:Body>
</soap:Envelope>

Note the 2 sessionId elements

Again, if the sessionId element doesn't exist at all, it works fine. Thanks in advance for any useful help.

Upvotes: 1

Views: 3258

Answers (2)

JLRishe
JLRishe

Reputation: 101652

If you can safely assume that sessionId will always be the only child of SessionHeader, then here is an easy way to accomplish this:

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

  <xsl:template match="SessionHeader[not(normalize-space(sessionId))]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <sessionId>9876543210</sessionId>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

If SessionHeader has no sessionId or an empty/all whitespace sessionId, it simply creates one with the predefined value. If it does already contain a sessionId with a value, then the identity template takes care of copying it.

Upvotes: 0

michael.hor257k
michael.hor257k

Reputation: 116957

I think (or rather guess) you want to do something like:

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="SessionHeader[not(sessionId)]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <sessionId><xsl:value-of select="9876543210"/></sessionId>
    </xsl:copy>
</xsl:template>

<xsl:template match="sessionId[not(text())]">
    <xsl:copy>
        <xsl:text>9876543210</xsl:text>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

This adds the value "9876543210" to the sessionId element if it's empty or creates a new sessionId element with the above value if it doesn't exist. Otherwise the default identity transforn template will copy the existing sessionId element, along with its existing value.

Upvotes: 1

Related Questions