i've the below XML document, where some cals table has to be created.
<table frame="none">
<tgroup cols="5" align="left" colsep="1" rowsep="1">
<colspec colwidth="20pt" colname="c1"/>
<colspec colwidth="70pt" colname="c2"/>
<colspec colwidth="10pt" colname="c3"/>
<colspec colwidth="20pt" colname="c4"/>
<colspec colwidth="75pt" colname="c5"/>
<thead>
<row>
<entry>
<para>Item</para>
</entry>
<entry align="center">
<para>Injury</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>Percentage of loss of earning capacity</para>
</entry>
<entry>
<para/>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>1.</para>
</entry>
<entry>
<para>Loss of 2 limbs ...................................................................</para>
</entry>
<entry morerows="7">
<para>}</para>
</entry>
<entry morerows="7">
<para>100</para>
</entry>
<entry morerows="7">
<para></para>
</entry>
</row>
<row>
<entry>
<para>2.</para>
</entry>
<entry>
<para>Loss of both hands or of all fingers and both thumbs ...</para>
</entry>
</row>
<row>
<entry>
<para>3.</para>
</entry>
<entry>
<para>Loss of both feet ................................................................</para>
</entry>
</row>
<row>
<entry>
<para>4.</para>
</entry>
<entry>
<para>Total loss of sight ...............................................................</para>
</entry>
</row>
<row>
<entry>
<para>5.</para>
</entry>
<entry>
<para>Total paralysis ....................................................................</para>
</entry>
</row>
<row>
<entry>
<para>6.</para>
</entry>
<entry>
<para>Injuries resulting in being permanently bedridden .......</para>
</entry>
</row>
<row>
<entry>
<para>7.</para>
</entry>
<entry>
<para>Paraplegia ..........................................................................</para>
</entry>
</row>
<row>
<entry>
<para>8.</para>
</entry>
<entry>
<para>Any other injury causing permanent total disablement ...</para>
</entry>
</row>
<row>
<entry>
<para>9.</para>
</entry>
<entry>
<para>Loss of arm at shoulder ....................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>75</para>
</entry>
<entry>
<para>80 (preferred hand)</para>
</entry>
</row>
<row>
<entry>
<para>10.</para>
</entry>
<entry>
<para>Ankylosis of shoulder joint—</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para/>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para/>
</entry>
<entry>
<para>in optimum position .....................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>35</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para/>
</entry>
<entry>
<para>in worst position ............................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>55</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>11.</para>
</entry>
<entry>
<para>Loss of arm between elbow and shoulder .......................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>75</para>
</entry>
<entry>
<para>80 (preferred hand)</para>
</entry>
</row>
<row>
<entry>
<para>12.</para>
</entry>
<entry>
<para>Loss of arm at elbow ..........................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>75</para>
</entry>
<entry>
<para>80 (preferred hand)</para>
</entry>
</row>
<row>
<entry>
<para>13.</para>
</entry>
<entry>
<para>Ankylosis of the elbow joint—</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para/>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para/>
</entry>
<entry>
<para>in optimum position .....................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>30</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para/>
</entry>
<entry>
<para>in worst position ............................................................</para>
</entry>
<entry>
<para/>
</entry>
<entry>
<para>50</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>14.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
here i've to create a table as shown in the below picture
i know its not a good idea to ask for code directly, i tried for normal tables(which were done), but i'm really unable to know how to do a cals table in xslt. please let me know how i can achieve doing these cals table.
Thanks
You say in a comment that you're looking for HTML output - well the input XML you're starting with has the right structure to convert directly into an HTML table with a 1-1 mapping of element names, you just need to turn the morerows="n" of the source format into a rowspan="n+1" in the HTML
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*" />
<xsl:output method="html" indent="yes" />
<!-- these nodes have the same names in HTML -->
<xsl:template match="table | thead | tbody">
<xsl:copy><xsl:apply-templates /></xsl:copy>
</xsl:template>
<!-- row becomes tr -->
<xsl:template match="row">
<tr><xsl:apply-templates /></tr>
</xsl:template>
<!-- entry becomes td -->
<xsl:template match="entry">
<td><xsl:apply-templates select="#morerows|node()" /></td>
</xsl:template>
<xsl:template match="entry/#morerows">
<xsl:attribute name="rowspan" select="1 + ." />
</xsl:template>
</xsl:stylesheet>
We rely here on the default template rules for nodes that don't have an explicit template, which will process children recursively in the case of elements and output the text in the case of text nodes.
You've tagged the question XSLT 2.0 but for the record this is almost an XSLT 1.0 stylesheet, the only thing you'd have to change is that xsl:attribute doesn't take a select in 1.0, so instead of <xsl:attribute name="rowspan" select="..." /> you'd need <xsl:attribute name="rowspan"><xsl:value-of select="..." /></xsl:attribute>.
Related
I'm trying to remove attribute whose value ="remove_it"
but not able to find a way
This is Input xml
<row>
<entry>
<p type="some1">
<t>This is text</t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
</row>
<row>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
</row>
<row>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
<entry>
<p type="remove_it">
<t> </t>
</p>
</entry>
</row>
</tbody>
</tgroup>
</table>
<p>
<t> </t>
</p>
</body>
</section>
want something like
<tgroup>
<tbody>
<row>
<entry>
<p type="some1">
<t>This is text</t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
</row>
<row>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
</row>
<row>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
<entry>
<p>
<t> </t>
</p>
</entry>
</row>
</tbody>
</tgroup>
</table>
<p>
<t> </t>
</p>
</body>
</section>
what i have been trying
<xsl:template match="sc:entry[(child::*[local-name()='p'][#type='_para'])]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sc:entry[(child::*[local-name()='p'][#type='_para'])]">
but this remove the entire node, I just want to remove attribute of p whose parent is entry
Is there any way I can only remove attribute of those value = "remove_it"
Thanks in advance!!
I just want to remove attribute of p whose parent is entry
Consider this example:
XML
<root>
<row>
<entry>
<p type="some1">
<t>This is text</t>
</p>
</entry>
<entry>
<p type="remove_it">
<t/>
</p>
</entry>
<entry>
<p type="remove_it">
<t/>
</p>
</entry>
</row>
<row>
<entry>
<p type="remove_it">
<t/>
</p>
</entry>
<entry>
<p type="keep_it">
<t/>
</p>
</entry>
<entry>
<p type="remove_it">
<t/>
</p>
</entry>
<entry>
<p type="remove_it">
<t/>
</p>
</entry>
</row>
</root>
XSLT 3.0
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="entry/p/#type[.='remove_it']"/>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<entry>
<p type="some1">
<t>This is text</t>
</p>
</entry>
<entry>
<p>
<t/>
</p>
</entry>
<entry>
<p>
<t/>
</p>
</entry>
</row>
<row>
<entry>
<p>
<t/>
</p>
</entry>
<entry>
<p type="keep_it">
<t/>
</p>
</entry>
<entry>
<p>
<t/>
</p>
</entry>
<entry>
<p>
<t/>
</p>
</entry>
</row>
</root>
Note:
You should never have to use a hack like *[local-name()='p']. If your input nodes are in a namespace, then deal with the namespace properly - see: XSLT Transform doesn't work until I remove root node.
Sorting the same field values from xml to top and rest field values to bottom.
this is my input to xslt:
<?xml version='1.0' encoding='UTF-8'?>
<feed>
<entry>
<name>David</name>
<updated>AA123</updated>
<title>BB123</title>
</entry>
<entry>
<name>John</name>
<updated>AA123</updated>
<title>AA123</title>
</entry>
<entry>
<name>Jenny</name>
<updated>CC789</updated>
<title>TT789</title>
</entry>
<entry>
<name>Dan</name>
<updated>CC456</updated>
<title>HH456</title>
</entry>
<entry>
<name>Steve</name>
<updated>CC456</updated>
<title>CC456</title>
</entry>
<entry>
<name>Jenny</name>
<updated>AB456</updated>
<title>DD789</title>
</entry>
</feed>
Expected Output:
<?xml version='1.0' encoding='UTF-8'?>
<feed>
<entry>
<name>John</name>
<updated>AA123</updated>
<title>AA123</title>
</entry>
<entry>
<name>Steve</name>
<updated>CC456</updated>
<title>CC456</title>
</entry>
<entry>
<name>David</name>
<updated>AA123</updated>
<title>BB123</title>
</entry>
<entry>
<name>Dan</name>
<updated>CC456</updated>
<title>HH456</title>
</entry>
<entry>
<name>Jenny</name>
<updated>AB456</updated>
<title>DD789</title>
</entry>
<entry>
<name>Jenny</name>
<updated>CC789</updated>
<title>TT789</title>
</entry>
</feed>
Below XSLT is not SORTING in correct way:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/feed">
<Customer>
<xsl:for-each-group select="entry" group-by="updated">
<xsl:for-each-group select="current-group()" group-by="title">
<xsl:copy-of select="current-group()"/>
<xsl:apply-templates>
<xsl:sort select="updated"/>
<xsl:sort select="title"/>
</xsl:apply-templates>
</xsl:for-each-group>
</xsl:for-each-group>
</Customer>
</xsl:template>
</xsl:stylesheet>
I have a requirement to SORT same FIELD values of field name "updated" and "title". If both the field values are same then it should come first in the OUTPUT XML and then later the different field value.
If I understand correctly, you want to do:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/feed">
<feed>
<xsl:perform-sort select="entry">
<xsl:sort select="number(updated = title)" data-type="number" order="descending"/>
</xsl:perform-sort>
</feed>
</xsl:template>
</xsl:stylesheet>
I have challenge to add xml tags dynamically based on count of one xml tag and also should not allow duplicates (I am using XSLT 1.0). For ex: I have 3 Creditor records in "CreditorPPContractParts" section in below xml as shown in test data.
<PPPrivPropertyLine>
<InsuredProperties>
<Entry>
<Buildings>
<Entry>
<AlarmClass>None_De</AlarmClass>
<InterestType>OwnerOccupied_De</InterestType>
<BuildingStandard_De>Normal</BuildingStandard_De>
</Entry>
</Buildings>
<ContractParts>
<Entry>
<CreditorPPContractParts>
<Entry>
<Creditor>
<Contact>
<AddressBookUID>D73GLX</AddressBookUID>
</Contact>
</Creditor>
</Entry>
<Entry>
<Creditor>
<Contact>
<AddressBookUID>OAS5OE</AddressBookUID>
</Contact>
</Creditor>
</Entry>
<Entry>
<Creditor>
<Contact>
<AddressBookUID>OAS5OE</AddressBookUID>
</Contact>
</Creditor>
</Entry>
</CreditorPPContractParts>
</Entry>
</ContractParts>
</Entry>
</InsuredProperties>
<PolicyContactRoles></PolicyContactRoles>
</PPPrivPropertyLine>
Now I have to create 3 entries in 'PolicyContactRoles' in same xml like below format since I've 3 creditor records above. We may have more than 3 creditor records but we need to add based on the creditor records count. As I said above we should not allow duplicates. We have one duplicate creditor record. so output should be 2 creditor entries.
<PolicyContactRoles>
<Entry>
<AccountContactRole>
<Subtype>Creditor_De</Subtype>
<AccountContact>
<Contact>
<AddressBookUID>D73GLX</AddressBookUID>
</Contact>
</AccountContact>
</AccountContactRole>
<Subtype>PolicyCreditor_De</Subtype>
</Entry>
<Entry>
<AccountContactRole>
<Subtype>Creditor_De</Subtype>
<AccountContact>
<Contact>
<AddressBookUID>OAS5OE</AddressBookUID>
</Contact>
</AccountContact>
</AccountContactRole>
<Subtype>PolicyCreditor_De</Subtype>
</Entry>
</PolicyContactRoles>
I have done it using below XSLT script. but could not able to avoid the duplicates. Please help me out, thank you!
<xsl:template match="PolicyContactRoles">
<xsl:copy>
<xsl:apply-templates select="//Creditor" mode="pcr"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Creditor" mode="pcr">
<Entry>
<AccountContactRole>
<Subtype>Creditor_De</Subtype>
<AccountContact>
<Contact>
<xsl:copy-of select=".//AddressBookUID"/>
</Contact>
</AccountContact>
</AccountContactRole>
<Subtype>PolicyCreditor_De</Subtype>
</Entry>
</xsl:template>
And also, please use this XSLT Fiddle:https://xsltfiddle.liberty-development.net/pNEj9dH/13
Use Muenchian grouping to get only distinct creditors:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="creditor" match="Creditor" use="Contact/AddressBookUID" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="PolicyContactRoles">
<xsl:copy>
<xsl:for-each select="//Creditor[count(. | key('creditor', Contact/AddressBookUID)[1]) = 1]">
<Entry>
<AccountContactRole>
<Subtype>Creditor_De</Subtype>
<AccountContact>
<Contact>
<xsl:copy-of select="Contact/AddressBookUID"/>
</Contact>
</AccountContact>
</AccountContactRole>
<Subtype>PolicyCreditor_De</Subtype>
</Entry>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I have an xml file with two "sets" of data that I need to merge into a table showing old vs new. I'm doing this by processing only new data, and for each piece of new data, grabbing the accompanying old piece. My question is how to properly store my current position in the new set so that I can grab the matching data from the old set. The real challenge I'm having is around nested elements, where position() isn't as useful. So, given the following simplified xml, where I know 100% for sure that there will be a perfectly matching tag set in New and Old...
<doc>
<New>
<Para>New info 1</Para>
<Para>New info 2</Para>
<List>
<Li>New Point 1</Li>
<Li>New Point 2</Li>
<Li>New Point 3</Li>
</List>
<Para>New info 3</Para>
<List>
<Li>New Point 4</Li>
<Li>New Point 5</Li>
<Li>New Point 6
<List>
<Li>New nested Point 1</Li>
<Li>New nested Point 2</Li>
<Li>New nested Point 3</Li>
</List>
</Li>
</List>
</New>
<Old>
<Para>Old info 1</Para>
<Para>Old info 2</Para>
<List>
<Li>Old Point 1</Li>
<Li>Old Point 2</Li>
<Li>Old Point 3</Li>
</List>
<Para>Old info 3</Para>
<List>
<Li>Old Point 4</Li>
<Li>Old Point 5</Li>
<Li>Old Point 6
<List>
<Li>Old nested Point 1</Li>
<Li>Old nested Point 2</Li>
<Li>Old nested Point 3</Li>
</List>
</Li>
</List>
</Old>
I want to merge and output the info in an html-like table.
<table>
<row>
<entry>New Info 1</entry>
<entry>Old Info 1</entry>
</row>
<row>
<entry>New Info 2</entry>
<entry>Old Info 2</entry>
</row>
<row>
<entry>
<list>
<li>New Point 1</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 1</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New Point 2</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 2</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New Point 3</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 3</li>
</list>
</entry>
</row>
<row>
<entry>New Info 3</entry>
<entry>Old Info 3</entry>
</row>
<row>
<entry>
<list>
<li>New Point 4</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 4</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New Point 5</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 5</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New Point 6</li>
</list>
</entry>
<entry>
<list>
<li>Old Point 6</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New nested Point 1</li>
</list>
</entry>
<entry>
<list>
<li>Old nested Point 1</li >
</entry>
</row>
<row>
<entry>
<list>
<li>New nested Point 2</li>
</list>
</entry>
<entry>
<list>
<li>Old nested Point 2</li>
</list>
</entry>
</row>
<row>
<entry>
<list>
<li>New nested Point 3</li>
</list>
</entry>
<entry>
<list>
<li>Old nested Point 3</li>
</list>
</entry>
</row>
</table>
It's only nested elements that are problematic. For everything else I can store my position within <New> and apply templates on the corresponding <Old> data, but position() becomes less useful when nested.
Any ideas on how to effectively store my position within <New> so that I can process the matching <Old> element? I'm using XSLT 1.
Since your example only deals with the top-level elements in each branch, the requested result can be accomplished by:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="old" match="id" use="." />
<xsl:variable name="old" select="/doc/Old" />
<xsl:template match="/doc">
<table>
<xsl:apply-templates select="New/Para | New/List"/>
</table>
</xsl:template>
<xsl:template match="Para">
<xsl:variable name="i" select="count(preceding-sibling::Para)" />
<row>
<entry>
<xsl:value-of select="."/>
</entry>
<entry>
<xsl:value-of select="$old/Para[$i + 1]"/>
</entry>
</row>
</xsl:template>
<xsl:template match="List">
<xsl:variable name="i" select="count(preceding-sibling::List)" />
<row>
<entry>
<xsl:copy-of select="."/>
</entry>
<entry>
<xsl:copy-of select="$old/List[$i + 1]"/>
</entry>
</row>
</xsl:template>
</xsl:stylesheet>
Matching individual leaf nodes by their position in their respective tree would be much more complicated, I think.
Edit:
I do need to match individual nodes unfortunately.
As I said, this is going to be much more complex - especially since you cannot use an extension function to dynamically evaluate a string into a path expression.
Here, we'll do a preliminary pass to process nodes in the Old branch and assign them a path attribute. This will enable us to call them by this attribute when processing the nodes in the New branch for the final output:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- first-pass -->
<xsl:variable name="old">
<xsl:apply-templates select="/doc/Old" mode="old"/>
</xsl:variable>
<xsl:variable name="old-set" select="exsl:node-set($old)" />
<xsl:template match="Para | Li" mode="old">
<node>
<xsl:attribute name="path">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()" />
<xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])" />
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name()=name(current())])" />
<xsl:text>]</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
<xsl:value-of select="text()"/>
</node>
<xsl:apply-templates select="*" mode="old"/>
</xsl:template>
<!-- output -->
<xsl:template match="/doc">
<table>
<xsl:apply-templates select="New"/>
</table>
</xsl:template>
<xsl:template match="Para | Li">
<xsl:variable name="path">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()" />
<xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])" />
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name()=name(current())])" />
<xsl:text>]</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="old-path" select="concat('doc[0]/Old[0]/', substring-after($path, 'doc[0]/New[0]/'))" />
<row>
<entry>
<xsl:value-of select="text()"/>
</entry>
<entry>
<xsl:value-of select="$old-set/node[#path=$old-path]"/>
</entry>
</row>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<table>
<row>
<entry>New info 1</entry>
<entry>Old info 1</entry>
</row>
<row>
<entry>New info 2</entry>
<entry>Old info 2</entry>
</row>
<row>
<entry>New Point 1</entry>
<entry>Old Point 1</entry>
</row>
<row>
<entry>New Point 2</entry>
<entry>Old Point 2</entry>
</row>
<row>
<entry>New Point 3</entry>
<entry>Old Point 3</entry>
</row>
<row>
<entry>New info 3</entry>
<entry>Old info 3</entry>
</row>
<row>
<entry>New Point 4</entry>
<entry>Old Point 4</entry>
</row>
<row>
<entry>New Point 5</entry>
<entry>Old Point 5</entry>
</row>
<row>
<entry>New Point 6
</entry>
<entry>Old Point 6
</entry>
</row>
<row>
<entry>New nested Point 1</entry>
<entry>Old nested Point 1</entry>
</row>
<row>
<entry>New nested Point 2</entry>
<entry>Old nested Point 2</entry>
</row>
<row>
<entry>New nested Point 3</entry>
<entry>Old nested Point 3</entry>
</row>
</table>
I have the following input XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
<row>
<code>NUMBER</code>
<value>001</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
<row>
<code>NUMBER</code>
<value>002</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
<row>
<code>NUMBER</code>
<value>003</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>NUMBER</code>
<value>004</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE</value>
</row>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
</data>
And it needs to be transformed to the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
<group>
<row>
<code>NUMBER</code>
<value>001</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>002</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>003</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>004</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE</value>
</row>
</group>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
</data>
The rules to be applied:
Some rows needs to be excluded from the grouping. These would be the rows that do not have the code NUMBER, FROM or TO.
When code NUMBER appears a new group starts
FROM and TO could be in different order
Rows that have to be exclude will always be in front and/or at the end of the to be grouped codes. It will never appear in between.
In XSLT 2.0 this would be easy and I have the solution, but in XSLT 1.0 I do not know where to start.
Here is a stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="row[code = 'TO' or code = 'FROM']" use="generate-id(preceding-sibling::row[code = 'NUMBER'][1])"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="row[code = 'NUMBER']">
<group>
<xsl:copy-of select=". | key('group', generate-id())"/>
</group>
</xsl:template>
<xsl:template match="row[code = 'FROM' or code = 'TO']"/>
</xsl:stylesheet>