xslt - Insert node into another XML, create new elements (or update existing ones) and reorder resulting document -
well, posting first question if i'm assiduously use site. i've been trying solution last 2 days without success. using of answers similar questions on site (this, this, this, this , many, many others) i've been able make progress complete (and correct!) solution still escapes me.
i have existing xml (file1.xml) have update based in 1 i'm generating (file2.xml): content of file2 has included on file1 respecting rules i'll state later, (content of files has been oversimplified show relevant elements) :
file1.xml
<?xml version="1.0" encoding="utf-8"?> <list> <decade lastyear="2012" firstyear="2011"> <year value="2012"> <issue year="2012" number="242" /> <issue year="2012" number="241" /> <issue year="2012" number="240" /> </year> <year value="2011"> <issue year="2011" number="238" /> <issue year="2011" number="237" /> <issue year="2011" number="236" /> <issue year="2011" number="235" /> </year> </decade> <decade lastyear="2010" firstyear="2001"> <year value="2010"> <issue year="2010" number="234" /> <issue year="2010" number="233" /> <issue year="2010" number="232" /> <issue year="2010" number="231" /> <issue year="2010" number="230" /> </year> <year value="2009"> <issue year="2009" number="229" /> <issue year="2009" number="228" /> <issue year="2009" number="227" /> <issue year="2009" number="226" /> <issue year="2009" number="225" /> </year> ... </decade> </list>
file2.xml
<?xml version="1.0" encoding="utf-8"?> <issue year="2013" number="245" /> ...
as said before, content of file2 must inserted on file1 rules respected:
- if issues' year don't exist on file1 (i.e., if inserting first issue of year), must created (already done)
- the new issue must inserted under corresponding year (already done)
- decade must updated reflect last inserted year (having problems 1 !)
- the issue element must ordered in descending order year and number
- if issues' year belongs new decade, 1 has created along corresponding child year , issue(s)
- in resulting document, elements must ordered in descending order: decade (lastyear), year (value) , issue (year , number)
i'm using saxon-he 9.4.0.6 , xsl i've done until one:
xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" exclude-result-prefixes="xs" version="2.0"> <xsl:output method="xml" omit-xml-declaration="yes" indent="no" encoding="utf-8"/> <xsl:variable name="up" select="document('../test/excelstory/file2.xml')"/> <xsl:variable name="year" select="$up/issue/@year" /> <xsl:template match="@* | node()" > <xsl:copy> <xsl:apply-templates select="@*|node()"> <xsl:sort select="//issue/@year" /> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="decade" > <xsl:copy> <xsl:apply-templates select="* | @*"/> <xsl:choose> <xsl:when test="year[1]/@value lt $year"> <year value="{$year}"/> </xsl:when> </xsl:choose> </xsl:copy> </xsl:template> <xsl:template match="year[@value=$year]"> <xsl:copy> <xsl:apply-templates select="* | @*"/> <xsl:apply-templates select="$up/*" /> </xsl:copy> </xsl:template> </xsl:stylesheet>
this stylesheet assumes content on file1.xml ordered when read (that's case).
i'm wondering if must more 1 pass using 'mode' first create decade according year (if necessary), insert year in correct decade (on second pass??), after insert issues on correct year (third pass??) , reorder elements (even pass??) or if required processing can made more efficiently (one or 2 passes). mr. michael key suggested somewhere else using xsl:for-each kind of processing don't know if fit better (easier?) in case.
even if question may seem similar others on stackoverflow, think there added complexity make worth reading (and may answering, hope!).
i'll grateful if can give ideas how proceed or if can point me additional resources.
what instead of trying add new issue
(s) combine of issue
s both files , recreate structure.
this might not work actual use case because said:
(content of files has been oversimplified show relevant elements)
but gives perspective and/or starting point.
you want add identity transform , replace xsl:copy-of
, xsl:perform-sort
xsl:apply-templates
. need update xsl:param
point external file.
xml input (modified add more years , change numbering testing)
<list> <decade lastyear="2012" firstyear="2011"> <year value="2012"> <issue year="2012" number="242" /> <issue year="2012" number="241" /> <issue year="2012" number="240" /> </year> <year value="2011"> <issue year="2011" number="238" /> <issue year="2011" number="237" /> <issue year="2011" number="236" /> <issue year="2011" number="235" /> </year> </decade> <decade lastyear="2010" firstyear="2001"> <year value="2010"> <issue year="2010" number="234" /> <issue year="2010" number="232" /> <issue year="2010" number="233" /> <issue year="2010" number="231" /> <issue year="2010" number="230" /> </year> <year value="2009"> <issue year="2009" number="229" /> <issue year="2009" number="228" /> <issue year="2009" number="227" /> <issue year="2009" number="226" /> <issue year="2009" number="225" /> </year> <year value="2001"> <issue year="2001" number="123" /> </year> </decade> </list>
xslt 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" exclude-result-prefixes="xs"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <!--this can changed point external xml file.--> <xsl:param name="up"> <issue year="2013" number="245" /> <issue year="2002" number="135" /> <issue year="2011" number="239" /> </xsl:param> <xsl:template match="/*"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:for-each-group select="($up/issue|*/*/issue)" group-by="floor((number(@year) - 1) div 10)"> <xsl:sort select="@year" data-type="number" order="descending"/> <decade lastyear="{max(current-group()/@year)}" firstyear="{min(current-group()/@year)}"> <xsl:for-each-group select="current-group()" group-by="@year"> <xsl:sort select="current-grouping-key()" data-type="number" order="descending"/> <year value="{current-grouping-key()}"> <xsl:perform-sort select="current-group()"> <xsl:sort select="@number" data-type="number" order="descending"/> </xsl:perform-sort> </year> </xsl:for-each-group> </decade> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
xml output
<list> <decade lastyear="2013" firstyear="2011"> <year value="2013"> <issue year="2013" number="245"/> </year> <year value="2012"> <issue year="2012" number="242"/> <issue year="2012" number="241"/> <issue year="2012" number="240"/> </year> <year value="2011"> <issue year="2011" number="239"/> <issue year="2011" number="238"/> <issue year="2011" number="237"/> <issue year="2011" number="236"/> <issue year="2011" number="235"/> </year> </decade> <decade lastyear="2010" firstyear="2001"> <year value="2010"> <issue year="2010" number="234"/> <issue year="2010" number="233"/> <issue year="2010" number="232"/> <issue year="2010" number="231"/> <issue year="2010" number="230"/> </year> <year value="2009"> <issue year="2009" number="229"/> <issue year="2009" number="228"/> <issue year="2009" number="227"/> <issue year="2009" number="226"/> <issue year="2009" number="225"/> </year> <year value="2002"> <issue year="2002" number="135"/> </year> <year value="2001"> <issue year="2001" number="123"/> </year> </decade> </list>
Comments
Post a Comment