Reputation: 1709
I'm a novice using XSLT. My requirement is best expressed through code. I'm looking for advice as to whether its possible to achieve my requirements through XLST. I'm not asking people to write code for me - although code advice would also be appreciated. I'm looking for pointers, e.g. "I need to chain multiple transforms". I'm using XSLT v1.0.
I have the input XML;
<Input>
<BarId>123</BarId>
<BarName>myname</BarName>
<FooName>dummy</FooName>
</Input>
...and need to create the output;
<Out>
<Foos>
<Foo>
<Id>100</Id>
<Name>dummy</Name>
</Foo>
</Foos>
<Bars>
<Bar>
<Id>123</Id>
<Name>myname</Name>
<FooId>100</FooId>
</Bar>
</Bars>
</Out>
Key Point:
Creating the Foo element is the part I need help with.
The Foo element(s) most precede the Bar element(s).
I'm not overly concerned about generating the Foo Id (i.e. in above example 100) - I have a few options here - but I guess the approach for populating the FooId on the Bar will depend on the overall approach?
(ps. apologies for vague title - Ill update accordingly based on resolution)
Upvotes: 2
Views: 157
Reputation: 10188
I am assuming you want to output a Foo
element with a unique ID for each distinct FooName
in the input. For this, you could use the Muenchian method:
First you'd build a xsl:key
using which you can quickly retrieve FooName
elements by their content.
<xsl:key name="FooNames" match="FooName" use="."/>
Using this key, you can then process only the first instance of each FooName, thus getting a distinct list. Here you can make use of the generate-id()
function for comparing nodes for identity.
<xsl:apply-templates select="//FooName
[generate-id() =
generate-id(key('FooNames', .)[1])]"/>
For generating the identifiers, if you don't care that the generated identifiers may vary from run to run, you can again use the generate-id()
function.
Putting it all together:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="FooNames" match="FooName" use="."/>
<xsl:template match="/">
<Out>
<Foos>
<xsl:apply-templates select="//FooName[generate-id() =
generate-id(key('FooNames', .)[1])]"/>
</Foos>
<Bars>
<xsl:apply-templates select="//Input"/>
</Bars>
</Out>
</xsl:template>
<xsl:template match="FooName">
<Foo>
<Id><xsl:value-of select="generate-id()"/></Id>
<Name><xsl:value-of select="."/></Name>
</Foo>
</xsl:template>
<xsl:template match="Input">
<Bar>
<Id><xsl:value-of select="BarId"/></Id>
<Name><xsl:value-of select="BarName"/></Name>
<FooId>
<xsl:value-of select="generate-id(key('FooNames', FooName)[1])"/>
</FooId>
</Bar>
</xsl:template>
</xsl:stylesheet>
With the following sample input:
<Inputs>
<Input>
<BarId>123</BarId>
<BarName>myname</BarName>
<FooName>dummy</FooName>
</Input>
<Input>
<BarId>124</BarId>
<BarName>anothername</BarName>
<FooName>dummy</FooName>
</Input>
<Input>
<BarId>125</BarId>
<BarName>yetanothername</BarName>
<FooName>dummy-two</FooName>
</Input>
</Inputs>
It will yield the output:
<Out>
<Foos>
<Foo>
<Id>id213296</Id>
<Name>dummy</Name>
</Foo>
<Foo>
<Id>id214097</Id>
<Name>dummy-two</Name>
</Foo>
</Foos>
<Bars>
<Bar>
<Id>123</Id>
<Name>myname</Name>
<FooId>id213296</FooId>
</Bar>
<Bar>
<Id>124</Id>
<Name>anothername</Name>
<FooId>id213296</FooId>
</Bar>
<Bar>
<Id>125</Id>
<Name>yetanothername</Name>
<FooId>id214097</FooId>
</Bar>
</Bars>
</Out>
Upvotes: 1
Reputation: 243459
It can be as simple as this, assuming a BarName
precedes its corresponding FooName
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<Out>
<Foos>
<xsl:apply-templates select="FooName"/>
</Foos>
<Bars>
<xsl:apply-templates select="BarName"/>
</Bars>
</Out>
</xsl:template>
<xsl:template match="FooName">
<Foo>
<Id><xsl:call-template name="makeFooId"/></Id>
<Name><xsl:value-of select="."/></Name>
</Foo>
</xsl:template>
<xsl:template match="BarName">
<Bar>
<Id><xsl:value-of select="preceding-sibling::BarId[1]"/></Id>
<Name><xsl:value-of select="."/></Name>
<FooId>
<xsl:call-template name="makeFooId">
<xsl:with-param name="pFoo" select="following-sibling::FooName[1]"/>
</xsl:call-template>
</FooId>
</Bar>
</xsl:template>
<xsl:template name="makeFooId">
<xsl:param name="pFoo" select="."/>
<!-- Replace the following line with your id - generating code -->
<xsl:text>100</xsl:text>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document:
<Input>
<BarId>123</BarId>
<BarName>myname</BarName>
<FooName>dummy</FooName>
</Input>
the wanted, correct result is produced:
<Out>
<Foos>
<Foo>
<Id>100</Id>
<Name>dummy</Name>
</Foo>
</Foos>
<Bars>
<Bar>
<Id>123</Id>
<Name>myname</Name>
<FooId>100</FooId>
</Bar>
</Bars>
</Out>
Upvotes: 0