Reputation: 3
I'm an XSLT newbie and am trying to transform the following XML to the next XML. I've commented significant changes needed in the second XML.
There are 2 major changes:
1) Since node2 element name repeats, I want to rename the second occurrence. 2) I want itemName attributes to each become an Element. 2a) For the [Customer ID] itemValue, I'll need it to be renamed 'CustomerID' when transformed to an Element.
In summary, I want the original to be transformed to a more table-like, columnar structure after being rendered in the browser.
<requestStatus>
<node1>
<clientId>4634</clientId>
<affiliateId>0</affiliateId>
<contactId>144756</contactId>
<requestId>64086</requestId>
<transNumber>F27A6A65</transNumber>
<status>11</status>
<paymentType>D</paymentType>
<amount>1.99</amount>
<contactEmail>[email protected]</contactEmail>
<templateName>Payment Form 2</templateName>
<createdBy>0</createdBy>
<paymentCnt>1</paymentCnt>
<nextPaymtDate/>
<recurringFrequency/>
<maxPayments>0</maxPayments>
<untilDate/>
<node2>
<node2>
<paymtId>56991</paymtId>
<paidAmount>1.99</paidAmount>
<paymentMethod>C</paymentMethod>
<paymentSeq>1</paymentSeq>
<submissionDate>08/04/2016</submissionDate>
<creditCardType>V</creditCardType>
<creditCardNumber>1111</creditCardNumber>
<cardHolder>Ronald McDonald</cardHolder>
<expirationMonth>1</expirationMonth>
<expirationYear>2017</expirationYear>
<achRequestId>0</achRequestId>
<accountNumber/>
<accountType/>
<depositType/>
<achSubmissionDate/>
<achEffectiveDate/>
</node2>
</node2>
<node3>
<node4>
<itemName>[FirstName]</itemName>
<itemValue>Ronald</itemValue>
</node4>
<node4>
<itemName>[LastName]</itemName>
<itemValue>McDonald</itemValue>
</node4>
<node4>
<itemName>[Email]</itemName>
<itemValue>[email protected]</itemValue>
</node4>
<node4>
<itemName>[Amount]</itemName>
<itemValue>1.99</itemValue>
</node4>
<node4>
<itemName>Customer ID</itemName>
<itemValue>CUSTOMER1</itemValue>
</node4>
<node4>
<itemName>Invoice Numbers</itemName>
<itemValue>INV10001,INV10002</itemValue>
</node4>
</node3>
</node1>
</requestStatus>
To this:
<requestStatus>
<node1>
<clientId>4634</clientId>
<affiliateId>0</affiliateId>
<contactId>144756</contactId>
<requestId>64086</requestId>
<transNumber>F27A6A65</transNumber>
<status>11</status>
<paymentType>D</paymentType>
<amount>1.99</amount>
<contactEmail>[email protected]</contactEmail>
<templateName>Payment Form 2</templateName>
<createdBy>0</createdBy>
<paymentCnt>1</paymentCnt>
<nextPaymtDate/>
<recurringFrequency/>
<maxPayments>0</maxPayments>
<untilDate/>
<node2>
<node2b> <!-- since node2 element was repeated, rename this as node2b -->
<paymtId>56991</paymtId>
<paidAmount>1.99</paidAmount>
<paymentMethod>C</paymentMethod>
<paymentSeq>1</paymentSeq>
<submissionDate>08/04/2016</submissionDate>
<creditCardType>V</creditCardType>
<creditCardNumber>1111</creditCardNumber>
<cardHolder>Ronald McDonald</cardHolder>
<expirationMonth>1</expirationMonth>
<expirationYear>2017</expirationYear>
<achRequestId>0</achRequestId>
<accountNumber/>
<accountType/>
<depositType/>
<achSubmissionDate/>
<achEffectiveDate/>
</node2b>
</node2>
<node3>
<FirstName>Ronald</FirstName> <!-- each itemName attribute to become a unique Element -->
<LastName>McDonald</LastName>
<Email>[email protected]</Email>
<Amount>1.99</Amount>
<CustomerID>CUSTOMER1</CustomerID>
<InvoiceNumbers>INV10001,INV10002</InvoiceNumbers>
</node3>
</node1>
Upvotes: 0
Views: 88
Reputation: 70648
I am not entirely sure of your precise requirements, but in situations like this where you are only transforming a portion of the XML, it is usually best to start with the identity transform
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Then, you only need to write templates for the nodes you wish to transform. So, for example, to rename the node2
to node2b
you would do this...
<xsl:template match="node2/node2">
<node2b>
<xsl:apply-templates select="@*|node()"/>
</node2b>
</xsl:template>
The node2/node2
match ensures only the child node2
is matched, not the parent. Replace these with your actual element names, of course.
For the node4
elements, you can use the xsl:element
element, together with Attribute Value Templates to create new elements, based on another value
<xsl:element name="{translate(itemName, '[] ', '')}">
<xsl:value-of select="itemValue" />
</xsl:element>
The translate
function here will strip out the specified symbols from the name. Do not that itemName
is an element, not an attribute.
Try this XSLT as starters:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node2/node2">
<node2b>
<xsl:apply-templates select="@*|node()"/>
</node2b>
</xsl:template>
<xsl:template match="node4">
<xsl:element name="{translate(itemName, '[] ', '')}">
<xsl:value-of select="itemValue" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1