Page 1 of 1

Adding element to the previous element

Posted: Mon Sep 08, 2008 11:03 am
by dani
Hi specialists!

Here is my problem.

I have the flat structure and i need to build the hierarchy. For example:

<LIST>
<Invoice>
<InvoiceNum>1</InvoiceNum>
<Delivery>
<DeliveryNum>22<DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum>3</InvoiceNum>
<Delivery>
<DeliveryNum>444<DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
</InvoiceNum>
<Delivery>
<DeliveryNum>22<DeliveryNum>
</Delivery>
</Invoice>
</LIST>


If "InvoiceNum" is empty, the "Dlivery" belongs to the previous "Invoice".

How can I add the Delivery to the previous element (Invoice)?

The structure must have this hierarchy:

<LIST>
<Invoice>
<InvoiceNum>1</InvoiceNum>
<Delivery>
<DeliveryNum>22<DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum>3</InvoiceNum>
<Delivery>
<DeliveryNum>444<DeliveryNum>
</Delivery>
<Delivery>
<DeliveryNum>22<DeliveryNum>
</Delivery>

</Invoice>
</LIST>





Thanks for help!

Re: Adding element to the previous element

Posted: Wed Sep 10, 2008 6:10 pm
by george
Hi,

Your sample is not well formed XML.
Assuming a sample like below:

Code: Select all


<LIST>
<Invoice>
<InvoiceNum>1</InvoiceNum>
<Delivery>
<DeliveryNum>1</DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum>2</InvoiceNum>
<Delivery>
<DeliveryNum>2</DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum/>
<Delivery>
<DeliveryNum>22</DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum>3</InvoiceNum>
<Delivery>
<DeliveryNum>3</DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum/>
<Delivery>
<DeliveryNum>33</DeliveryNum>
</Delivery>
</Invoice>
</LIST>
then the following stylesheet

Code: Select all


<?xml version="1.0"?>
<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="Invoice[InvoiceNum/text()]">
<xsl:variable name="id" select="generate-id(.)"/>
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
<xsl:apply-templates select="following-sibling::Invoice[
not(InvoiceNum/text()) and
$id=generate-id(preceding-sibling::Invoice[InvoiceNum/text()][1])
]/node()[not(self::InvoiceNum)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Invoice"/>
</xsl:stylesheet>
will give you

Code: Select all


<?xml version="1.0" encoding="utf-8"?><LIST>
<Invoice>
<InvoiceNum>1</InvoiceNum>
<Delivery>
<DeliveryNum>1</DeliveryNum>
</Delivery>
</Invoice>
<Invoice>
<InvoiceNum>2</InvoiceNum>
<Delivery>
<DeliveryNum>2</DeliveryNum>
</Delivery>


<Delivery>
<DeliveryNum>22</DeliveryNum>
</Delivery>
</Invoice>

<Invoice>
<InvoiceNum>3</InvoiceNum>
<Delivery>
<DeliveryNum>3</DeliveryNum>
</Delivery>


<Delivery>
<DeliveryNum>33</DeliveryNum>
</Delivery>
</Invoice>

</LIST>
Basically the stylesheet starts with a recursive copy template and adds two rules. One matches on the Invoices with an InvoiceNum element with some content and copies that together with the content of the following Invoice elements that have empty InvoiceNum elements (excluding those empty InvoiceNum elements). The other template rule matches on the other Invoice elements that are the ones with an empty InvoiceNum and output nothing as those were processed in the other template match.

Best Regards,
George