Adding element to the previous element

Here should go questions about transforming XML with XSLT and FOP.
dani
Posts: 1
Joined: Mon Sep 08, 2008 10:35 am

Adding element to the previous element

Post 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!
george
Site Admin
Posts: 2095
Joined: Thu Jan 09, 2003 2:58 pm

Re: Adding element to the previous element

Post 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
George Cristian Bina
Post Reply