Reputation: 35
I'm very much a beginner with xsl transformations
I have some xml that I need to insert an attribute into an element when that attribute doesn't 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>
The <Invoice>
element can have an Id attribute <Invoice Id="IR1564897">
How can I check the following.
<Refernce>DN1235588</Reference>
as the Id
<Reference>
Use the Value of the <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 is not outputting the full <Invoice>
element.
How can I correct 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 either one will always exist will this work to alternate between <Reference>
and <HoldingRef>
?
With the help of Alex: The following has worked for me to replace 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>
Upvotes: 1
Views: 6457
Reputation:
The shortest answer:
<xsl:template match="Invoice[not(@Id)]">
<Invoice Id="{(../DeliveryNote/Reference|
../DeliveryNote/HoldingRef)[1]}">
<xsl:apply-templates select="@* | node()"/>
</Invoice>
</xsl:template>
Upvotes: 6
Reputation: 3407
What 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 your <xsl:template match="Order/Documents/Invoice[not(@Id)]">
Upvotes: 0
Reputation: 2545
Give a try:
<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>
As for your questions:
The above is not outputting the full element. How can I correct this?
See my example.
If either one will always exist will this work to alternate between
<Reference>
and<HoldingRef>
?
Either with XPath (as in my example) or with xsl:choose
.
Upvotes: 0