XSL Conversion - Insert Attribute

I start very much with xsl conversions

I have xml that I need to insert an attribute into an element if this attribute does not exist.

Using the below xml as an example.

<Order Id="IR1598756" Status="2">
  <Details>
    <SomeInfo>Sample Data</SomeInfo>
  </Details>
  <Documents>
    <Invoice>
      <Date>15-02-2011</Date>
      <Time>11:22</Time>
      <Employee Id="159">James Morrison</Employee>
    </Invoice>
    <DeliveryNote>
      <Reference>DN1235588</Reference>
      <HoldingRef>HR1598785</HoldingRef>
      <Date>16-02-2011</Date>
      <Time>15:00</Time>
      <Employee Id="25">Javi Cortez</Employee>
    </DeliveryNote>
  </Documents>
</Order>

Desired output

<Order Id="IR1598756" Status="2">
  <Details>
    <SomeInfo>Sample Data</SomeInfo>
  </Details>
  <Documents>
    <Invoice Id="DN1235588">
      <Date>15-02-2011</Date>
      <Time>11:22</Time>
      <Employee Id="159">James Morrison</Employee>
    </Invoice>
  </Documents>
</Order>    

An element <Invoice>may have an id attribute<Invoice Id="IR1564897">

How can I check the following.

  • Make sure the attribute exists.
  • If not, insert the value <Refernce>DN1235588</Reference>asId
  • If not <Reference>Use value<HoldingRef>HR1598785</HoldingRef>

I was looking at implementing something like the following

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

  <xsl:template match="/">
    <xsl:apply-templates select="//Order"/>
  </xsl:template>

  <xsl:template match="Order/Documents/Invoice[not(@Id)]">
      <xsl:attribute name="Id">
        <xsl:value-of select="//Documents/DeliveryNote/Reference"/>
      </xsl:attribute>      
  </xsl:template>

The above does not output the complete element <Invoice>. How can i fix this?

  <xsl:if test="Order/Documents/DeliveryNote/Reference">
    <xsl:value-of select="//Documents/DeliveryNote/Reference"/>
  </xsl:if>
  <xsl:if test="Not(Order/Documents/DeliveryNote/Reference)">
    <xsl:value-of select="//Documents/DeliveryNote/HoldingRef"/>
  </xsl:if>

If any of them will always exist, will this work alternate between <Reference>and <HoldingRef>?

With the help of Alex: For me, replaced the attribute

  <xsl:template match="Order/Documents/Invoice[not(@Id)]">       
    <Invoice>
      <xsl:attribute name="Id">         
        <xsl:value-of Select="//Documents/DeliveryNote/Reference"/>
      </xsl:attribute>         
      <xsl:apply-templates select="@* | node()"/>
    </Invoice>
  </xsl:template>
+1
3

:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates select="//Order"/>
    </xsl:template>

    <!-- Match invoices without ids -->
    <!-- [DeliveryNote[Reference or HoldingRef] - defend against empty attributes -->
    <xsl:template match="Invoice[not(@id)][DeliveryNote[Reference or HoldingRef]]">
        <xsl:copy>
            <!-- create an attribute and fetch required data. In case Reference is present then insert reference
             otherwise - HoldingRef -->
            <xsl:attribute name="Id">
                <xsl:value-of select="following-sibling::DeliveryNote[1]/Reference |
                        following-sibling::DeliveryNote[1]/HoldingRef"/>
            </xsl:attribute>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="//DeliveryNote"/>

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

:

. ?

. .

, <Reference> <HoldingRef>?

XPath ( ), xsl:choose.

0

:

<xsl:template match="Invoice[not(@Id)]">
    <Invoice Id="{(../DeliveryNote/Reference|
                   ../DeliveryNote/HoldingRef)[1]}">
        <xsl:apply-templates select="@* | node()"/>
    </Invoice>
</xsl:template>
+6

How about this?

  <xsl:template match="Invoice[not(@Id)]">
    <xsl:element name="Invoice">
      <xsl:attribute name="Id">
        <xsl:variable name="REF" select="../DeliveryNote/Reference"/>
        <xsl:choose>
          <xsl:when test="not($REF)">
            <xsl:value-of select="../DeliveryNote/HoldingRef"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="../DeliveryNote/Reference"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:apply-templates select="*"/>
    </xsl:element>
  </xsl:template>

Use it instead <xsl:template match="Order/Documents/Invoice[not(@Id)]">

0
source

All Articles