Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Newbie - sorting input and selective output header/lines 1

Status
Not open for further replies.

razor1965

Programmer
Jun 24, 2010
2
GB
Hi, I'm a newbie to the world of XML/XSLT and I've been tasked with processing a XML file containing orders and effectively turning it into a headers and lines scenario. This is not exactly the case but it best demonstrates what I need to do.

I will have an XML file as follows:

<Orders>
<OrderDetail>
<OrderNo>123</OrderNo>
<ProductId>ABC1</ProductId>
</OrderDetail>
<OrderDetail>
<OrderNo>124</OrderNo>
<ProductId>ABC1</ProductId>
</OrderDetail>
<OrderDetail>
<OrderNo>123</OrderNo>
<ProductId>ABC2</ProductId>
</OrderDetail>
<OrderDetail>
<OrderNo>124</OrderNo>
<ProductId>ABC3</ProductId>
</OrderDetail>
</Orders>

And I need to get output similar to this:

<OrderHeader>
<OrderNo>123</OrderNo>
</OrderHeader>
<OrderLine>
<OrderNo>123</OrderNo>
<ProductId>ABC1</ProductId>
</OrderLine>
<OrderLine>
<OrderNo>123</OrderNo>
<ProductId>ABC2</ProductId>
</OrderLine>
<OrderHeader>
<OrderNo>124</OrderNo>
</OrderHeader>
<OrderLine>
<OrderNo>124</OrderNo>
<ProductId>ABC1</ProductId>
</OrderLine>
<OrderLine>
<OrderNo>124</OrderNo>
<ProductId>ABC3</ProductId>
</OrderLine>

Does anybody know how I can achieve this?

I think I need to do some use of xsl:sort to sort the stuff in the first place and then some variation of this code to only selectively output headers

<xsl:variable name="unique-list"
select="//OrderNo[not(.=following::OrderNo)]" />

<xsl:for-each select="$unique-list">
<xsl:value-of select="." />
</xsl:for-each>

Now please bear with me. I am an experienced procedural programmer and I'm trying to get into this (Its real BTW not 'homework').

Regards

Razor
 
[0] As a matter of opinion, the document required is, to a huge extension, an inferior design than the original in many aspects. But, I am not here to argue.

[1] This is how you do this kind of thing. (There may be some big gaps in the concepts you've to fill by yourself, as they are not that easy. But, once you see a valid implementation, at some point in time, it would appear obvious.) These are the two templates to accomplish the task together with the top-level xsl:key element. (I include xsl:eek:utput as well for your convenience.)
[tt]
<xsl:eek:utput method="xml" indent="yes" encoding="utf-8" />
<xsl:key name="x" match="OrderDetail" use="OrderNo" />
<xsl:template match="/">
<Orders>
<xsl:apply-templates select="Orders/OrderDetail">
<xsl:sort select="OrderNo" data-type="number" order="ascending" />
</xsl:apply-templates>
</Orders>
</xsl:template>
<xsl:template match="OrderDetail">
<xsl:if test="count(.|key('x',OrderNo)[1])=1">
<OrderHeader>
<OrderNo><xsl:value-of select="OrderNo" /></OrderNo>
</OrderHeader>
<xsl:for-each select="key('x',OrderNo)">
<OrderLine>
<OrderNo><xsl:value-of select="OrderNo" /></OrderNo>
<ProductId><xsl:value-of select="ProductId" /></ProductId>
</OrderLine>
</xsl:for-each>
</xsl:if>
</xsl:template>
[/tt]
 
Many thanks Tsuji. I will look at these new concepts and try and work them into my requirements.

Cheers

Razor
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top