I'm new in xml, sorry for the dumb question. I'm trying to create xsl template to convert Source xml to Destination. Actually it's almost done but I don't know how to enumerate <creator>'s correctly (creator#affil in Destination xml).
Source:
<?xml version="1.0" encoding="iso-8859-1"?>
<CREATORS>
<PERSON ROLE="CONTACT">
<PREFIX>Prof</PREFIX>
<FIRST_NAME>Mike</FIRST_NAME>
<MIDDLE_INITIALS>J</MIDDLE_INITIALS>
<LAST_NAME>Petrov</LAST_NAME>
<SUFFIX/>
<POSITION>Director</POSITION>
<EMAIL_1>pontorez#pontorez.ru</EMAIL_1>
<EMAIL_2>webmaster#pontorez.ru</EMAIL_2>
<URL>www.pontorez.ru</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>Finch Pavilion</ADDRESS_1>
<ADDRESS_2>Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="7091" ROLE="AUTHOR">
<PREFIX>Prof</PREFIX>
<FIRST_NAME>Mike</FIRST_NAME>
<MIDDLE_INITIALS>J</MIDDLE_INITIALS>
<LAST_NAME>Petrov</LAST_NAME>
<SUFFIX/>
<POSITION>Director</POSITION>
<EMAIL_1>pontorez#pontorez.ru</EMAIL_1>
<EMAIL_2>webmaster#pontorez.ru</EMAIL_2>
<URL>www.pontorez.ru</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>Finch Pavilion</ADDRESS_1>
<ADDRESS_2>Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE>Author footnote</FOOTNOTE>
</PERSON>
<PERSON ID="7094" ROLE="AUTHOR">
<PREFIX>Mrs</PREFIX>
<FIRST_NAME>Anne</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Spencer</LAST_NAME>
<SUFFIX/>
<POSITION/>
<EMAIL_1>aspencer#Hardware.co.uk</EMAIL_1>
<EMAIL_2/>
<URL/>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>SEO R&D Programme</ADDRESS_1>
<ADDRESS_2>Finch Pavilion, Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION>Oxfordshire</REGION>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="15756" ROLE="AUTHOR">
<PREFIX>Mr</PREFIX>
<FIRST_NAME>Ed</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Gantos</LAST_NAME>
<SUFFIX/>
<POSITION>Senior Medical Statistician</POSITION>
<EMAIL_1>santos#xxx.org.uk</EMAIL_1>
<EMAIL_2/>
<URL>http://www.isds.sxo.ac.uk/</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT>Head of SEO Support</DEPARTMENT>
<ORGANISATION>Centre for Statistics in Software</ORGANISATION>
<ADDRESS_1>Pearson College</ADDRESS_1>
<ADDRESS_2>Linton Road</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 6UD</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 112404</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 112424</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="7092" ROLE="AUTHOR">
<PREFIX>Dr</PREFIX>
<FIRST_NAME>Sherry</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Wilson</LAST_NAME>
<SUFFIX/>
<POSITION/>
<EMAIL_1>wilson#Hardware.co.uk</EMAIL_1>
<EMAIL_2/>
<URL/>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>SEO R&D Programme</ADDRESS_1>
<ADDRESS_2>Finch Pavilion, Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION>Oxfordshire</REGION>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<GROUP ID="????">
<GROUP_NAME>Bond team</GROUP_NAME>
<CONTACT_PERSON>Monica Bond</CONTACT_PERSON>
<EMAIL_1>mk#Hardware.dk</EMAIL_1>
<URL/>
<ADDRESS>
<DEPARTMENT>Nordic Hardware Centre</DEPARTMENT>
<ORGANISATION>Creyts, Dept 7512</ORGANISATION>
<ADDRESS_1>Blegdamsvej 219</ADDRESS_1>
<ADDRESS_2/>
<CITY>Copenhagen</CITY>
<ZIP>2900</ZIP>
<REGION/>
<COUNTRY CODE="DK">Denmark</COUNTRY>
<PHONE_1>+415 7667 7110</PHONE_1>
<PHONE_2>+415 1234 9429</PHONE_2>
<FAX_1>+415 7667 7007</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE>Group footnote</FOOTNOTE>
</GROUP>
<PERSON ID="3" ROLE="AUTHOR">
<PREFIX>Ms</PREFIX>
<FIRST_NAME>Monica</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Bond</LAST_NAME>
<SUFFIX/>
<POSITION>Director of the Hardware Information Management System</POSITION>
<EMAIL_1>mk#Hardware.dk</EMAIL_1>
<EMAIL_2/>
<URL>www.cc-ims.net</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT>Nordic Hardware Centre</DEPARTMENT>
<ORGANISATION>Creyts, Dept 7512</ORGANISATION>
<ADDRESS_1>Blegdamsvej 219</ADDRESS_1>
<ADDRESS_2/>
<CITY>Copenhagen</CITY>
<ZIP>2900</ZIP>
<REGION/>
<COUNTRY CODE="DK">Denmark</COUNTRY>
<PHONE_1>+415 7667 7110</PHONE_1>
<PHONE_2>+415 1234 9429</PHONE_2>
<FAX_1>+415 7667 7007</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
</CREATORS>
Destination:
<?xml version="1.0" encoding="utf-8"?>
<creatorGroup>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Mike</forenames>
<surnamePrefix>J</surnamePrefix>
<surname>Petrov</surname>
<note id="CD004002-note-0001">
<p>Author footnote</p>
</note>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Anne</forenames>
<surname>Spencer</surname>
</creator>
<creator affil="CD004002-aff-0002" creatorRole="author">
<forenames>Ed</forenames>
<surname>Gantos</surname>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Sherry</forenames>
<surname>Wilson</surname>
</creator>
<creator affil="CD004002-aff-0003" type="collaboration" creatorRole="author">
<collab>Bond team</collab>
</creator>
<creator affil="CD004002-aff-0003" creatorRole="author">
<forenames>Monica</forenames>
<surname>Bond</surname>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="contact">
<honorifics>Prof</honorifics>
<forenames>Mike</forenames>
<surnamePrefix>J</surnamePrefix>
<surname>Petrov</surname>
<jobTitle>Director</jobTitle>
<email>pontorez#pontorez.ru</email>
<email>webmaster#pontorez.ru</email>
</creator>
<affiliation id="CD004002-aff-0001" countryCode="GB">
<orgName>Example</orgName>
<address>
<street>Finch Pavilion</street>
<street>Middle Way</street>
<city>Oxford</city>
<country>UK</country>
<postCode>OX9 7LG</postCode>
</address>
</affiliation>
<affiliation id="CD004002-aff-0002" countryCode="GB">
<orgName>Centre for Statistics in Software</orgName>
<orgDiv>Head of SEO Support</orgDiv>
<address>
<street>Pearson College</street>
<street>Linton Road</street>
<city>Oxford</city>
<country>UK</country>
<postCode>OX9 6UD</postCode>
</address>
</affiliation>
<affiliation id="CD004002-aff-0003" countryCode="DK">
<collabContact>Monica Bond</collabContact>
<orgName>Creyts, Dept 7512</orgName>
<orgDiv>Nordic Hardware Centre</orgDiv>
<address>
<street>Blegdamsvej 219</street>
<city>Copenhagen</city>
<country>Denmark</country>
<postCode>2900</postCode>
</address>
</affiliation>
</creatorGroup>
XSL stylesheet that I created:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="affiliations" match="ORGANISATION" use="."/>
<xsl:template name="kreator">
<xsl:variable name="affid">
<!-- The numbering problem is in the below line: -->
<xsl:number format="0001" value="position()"/>
</xsl:variable>
<xsl:variable name="role">
<xsl:choose>
<xsl:when test="#ROLE='AUTHOR' or name()='GROUP'">author</xsl:when>
<xsl:otherwise>contact</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<creator affil="CD004002-aff-{$affid}">
<xsl:if test="GROUP_NAME!=''">
<xsl:attribute name="type">collaboration</xsl:attribute>
</xsl:if>
<xsl:attribute name="creatorRole">
<xsl:value-of select="$role"/>
</xsl:attribute>
<xsl:if test="$role='contact'">
<honorifics>
<xsl:value-of select="PREFIX"/>
</honorifics>
</xsl:if>
<xsl:if test="GROUP_NAME!=''">
<collab>
<xsl:value-of select="GROUP_NAME"/>
</collab>
</xsl:if>
<xsl:if test="FIRST_NAME">
<forenames>
<xsl:value-of select="FIRST_NAME"/>
</forenames>
</xsl:if>
<xsl:if test="MIDDLE_INITIALS!=''">
<surnamePrefix>
<xsl:value-of select="MIDDLE_INITIALS"/>
</surnamePrefix>
</xsl:if>
<xsl:if test="LAST_NAME">
<surname>
<xsl:value-of select="LAST_NAME"/>
</surname>
</xsl:if>
<xsl:if test="FOOTNOTE!='' and name()='PERSON'">
<note id="CD004002-note-{$affid}">
<p>
<xsl:value-of select="FOOTNOTE"/>
</p>
</note>
</xsl:if>
<xsl:if test="$role='contact'">
<jobTitle><xsl:value-of select="POSITION"/></jobTitle>
<email><xsl:value-of select="EMAIL_1"/></email>
<email><xsl:value-of select="EMAIL_2"/></email>
</xsl:if>
</creator>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="/CREATORS">
<xmp>
<creatorGroup>
<!-- list of creators: -->
<xsl:for-each select="PERSON[#ROLE='AUTHOR'] | GROUP">
<xsl:call-template name="kreator"/>
</xsl:for-each>
<xsl:for-each select="PERSON[#ROLE='CONTACT']">
<xsl:call-template name="kreator"/>
</xsl:for-each>
<!-- list of affiliations: -->
<xsl:for-each select="//ORGANISATION[generate-id(.)=generate-id(key('affiliations', .))]">
<affiliation>
<xsl:attribute name="id">
CD004002-aff-000<xsl:value-of select="position()"/>
</xsl:attribute>
<xsl:attribute name="countryCode">
<xsl:value-of select="../COUNTRY/#CODE"/>
</xsl:attribute>
<xsl:if test="../../CONTACT_PERSON">
<collabContact>
<xsl:value-of select="../../CONTACT_PERSON"/>
</collabContact>
</xsl:if>
<orgName>
<xsl:value-of select="."/>
</orgName>
<xsl:if test="../DEPARTMENT!=''">
<orgDiv>
<xsl:value-of select="../DEPARTMENT"/>
</orgDiv>
</xsl:if>
<address>
<street>
<xsl:value-of select="../ADDRESS_1"/>
</street>
<xsl:if test="../ADDRESS_2!=''">
<street>
<xsl:value-of select="../ADDRESS_2"/>
</street>
</xsl:if>
<city>
<xsl:value-of select="../CITY"/>
</city>
<country>
<xsl:value-of select="../COUNTRY"/>
</country>
<postCode>
<xsl:value-of select="../ZIP"/>
</postCode>
</address>
</affiliation>
<xsl:text>
</xsl:text>
</xsl:for-each>
</creatorGroup>
</xmp>
</xsl:template>
</xsl:stylesheet>
I.e. I want to get <creator> numbering like the below:
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0002" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0003" type="collaboration" creatorRole="author"/>
<creator affil="CD004002-aff-0003" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="contact"/>
While my current XSL stylesheet produces wrong #affil's:
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0002" type="collaboration" creatorRole="author"/>
<creator affil="CD004002-aff-0002" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="contact"/>
Can you help please? Thanks.
Your problem is that when you do:
<xsl:call-template name="kreator" />
then you do it in the context of the <PERSON> or <GROUP> you are currently handling.
This means that position() will tell you the position of those elements. It cannot magically know that you are interested in the position of the first <ORGANISATION> that matches the current one.
And this means you must iterate all <ORGANISATION>s much the same way you do it to calculate the <affiliation> attribute #id:
<xsl:variable name="affid">
<xsl:variable name="org" select="ADDRESS/ORGANISATION" />
<xsl:for-each select="//ORGANISATION[
generate-id()
=
generate-id(key('affiliations', .)[1])
]">
<xsl:if test=". = $org">
<xsl:number format="0001" value="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
Note the use of <xsl:if> to make sure that the variable eventually contains only one value, even though you are looking through all of them.
For larger documents, you could introduce another key:
<xsl:key name="organisations" match="ORGANISATION" use="'all'" />
and use that as a drop-in replacement for all the comparatively inefficient "//ORGANISATION" expressions, e.g. instead of:
<xsl:for-each select="//ORGANISATION">
<!-- ... -->
</xsl:for-each>
use:
<xsl:for-each select="key('organisations', 'all')">
<!-- ... -->
</xsl:for-each>
Related
I am struggling with XSLT and have been for days. I'm in the process of modifying a previous coworkers python code that transforms many different JSON files into xml and finally into kml. I'm within a hairs breadth of wrapping this up and, of course, the one part I can't get my head around is what's left.
I have an xml file with this structure:
<?xml version="1.0" ?>
<document xmlns="http://ws.wso2.org/dataservice">
<group>
<display_name>Housing</display_name>
<id>Housing</id>
<item>
<id>5063</id>
<image_url>images/5063.jpg</image_url>
<latitude>40.354007</latitude>
<longitude>-74.666675</longitude>
<name>Stanworth Apartments</name>
</item>
.
. (Many items omitted)
.
</group>
<group>
<display_name>Buildings</display_name>
<id>Building</id>
<item>
<id>5025</id>
<image_url>images/5025.jpg</image_url>
<latitude>40.350066</latitude>
<longitude>-74.603464</longitude>
<name>Lyman Spitzer Building</name>
<name_alt>LSB</name_alt>
<organization_id>ORG418</organization_id>
</item>
.
. (Many items omitted)
.
</group>
<group>
.
. (Many groups omitted)
.
</group>
<group>
<display_name>Accessible Features</display_name>
<id>Entryway</id>
<item>
<description>Accessible entryway</description>
<id>E028</id>
<latitude>40.349159</latitude>
<longitude>-74.658629</longitude>
<name>E028</name>
</item>
<item>
<description>Accessible entryway</description>
<id>E029</id>
<latitude>40.349398</latitude>
<longitude>-74.658517</longitude>
<name>E029</name>
</item>
</group>
<group>
<display_name>Accessible Features</display_name>
<id>Route</id>
<item>
<description>Accessible pathway</description>
<id>R054</id>
<name>R054</name>
<steps>-74.66032495749012,40.3489269473544</steps>
<steps>-74.6602836233495,40.34888813533125</steps>
</item>
<item>
<description>Accessible pathway</description>
<id>R055</id>
<name>R055</name>
<steps>-74.66023036637355,40.34884827131961</steps>
<steps>-74.66018651597699,40.34881015960344</steps>
</item>
<item>
<description>Accessible pathway</description>
<id>R072</id>
<name>R072</name>
<steps>-74.66101885775542,40.34737535360176</steps>
<steps>-74.6610915120654,40.34740600913134</steps>
<steps>-74.66187000551304,40.34717392492537</steps>
</item>
</group>
</document>
Each "group" is transformed into a Folder in the final KML file.
<Folder id="Housing">
<name>Housing</name>
<Placemark id="_0288">
.
. (Many lines omitted)
.
The goal is to create one Folder "id='Accessible" with the contents of two groups. The group with id='Entryway' and the group with id='Route. The desired output would be:
<Folder id="Accessible">
<name>Accessible Features</name>
<Placemark id="_E001">
<name>E001</name>
<description><![CDATA[<div><p>Accessible entryway</p></div>]]></description>
<styleUrl>#entryway</styleUrl>
<Point>
<coordinates>-74.663266, 40.348289,0</coordinates>
</Point>
</Placemark>
<Placemark id="_E002">
<name>E002</name>
<description><![CDATA[<div><p>Accessible entryway</p></div>]]></description>
<styleUrl>#entryway</styleUrl>
<Point>
<coordinates>-74.662252, 40.348057,0</coordinates>
</Point>
</Placemark>
.
. then have the items from the group with id='Route'
.
<Placemark id="_R002">
<name>Accessible Routes</name>
<description><![CDATA[<div><p>Accessible pathway</p></div>]]></description>
<styleUrl/>
<Style>
<LineStyle>
<color>FFFF0000</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<coordinates>
-74.65135187837255,40.34699608960065
-74.65134698312161,40.34698651192196
</coordinates>
</LineString>
</Placemark>
<Placemark id="_R003">
<name>Accessible Routes</name>
<description><![CDATA[<div><p>Accessible pathway</p></div>]]></description>
<styleUrl/>
<Style>
<LineStyle>
<color>FFFF0000</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<coordinates>
-74.65135184561255,40.34699603789065
-74.65134698312256 44.34698634192100
</coordinates>
</LineString>
</Placemark>
.
. more than 66,000 lines omitted
.
</Folder>
I've written the XSLT to transform the XML into these KML Folders and the only thing left to do is get them under the same folder.
What I've been trying to do is move all of the items from the group with id='Route' into the group with id='Entryway.
In my xslt file is an apply-templates at the group nodes.
<xsl:apply-templates select="ds:group">
<xsl:sort select="ds:display_name"/>
</xsl:apply-templates>
This is picked up by the template match for each group.
<xsl:template match="ds:group">
At which point I'm lost. I'll post my code but it is only going to confuse and depress you.
<xsl:template match="ds:group">
<xsl:choose>
<xsl:when test="not(ds:id = 'Route') and not(ds:id = 'Entryway')">
<Folder id="{ds:id}">
<name>
<xsl:value-of select="ds:display_name"/>
</name>
<xsl:apply-templates select="ds:item">
<xsl:sort select="ds:name"/>
</xsl:apply-templates>
</Folder>
</xsl:when>
<xsl:when test="ds:id = 'Entryway'">
<Folder id='Accessible'>
<name>
<xsl:value-of select="ds:display_name"/>
</name>
<xsl:apply-templates select="ds:item">
<xsl:sort select="ds:name"/>
</xsl:apply-templates>
</Folder>
</xsl:when>
<xsl:when test="ds:id = 'Route'">
<!-- Copy all of current node to Entryway node -->
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I don't think I'm going about this the right way. By the time the XSLT process gets to the group with id='Route' the KML Folder for Entryway has already been written. I'm at a dead end. Can I union two groups together based on the value of "id"? Conceptually the idea would be: <xsl:template match="ds:id='Route' | ds:id='Entryway'"> But that doesn't even compile.
Can I copy all of the elements of the group (id='Route') to the group (id='Entryway') after the first group has been processed?
Thank you in advance for your time and attention.
George
I think you need to "step" in at the document level and do e.g.
<xsl:template match="ds:document">
<Folder id='Accessible'>
<xsl:apply-templates select="ds:group[ds:id = 'Entryway' or ds:id = 'Route']"/>
</Folder>
<!-- process other ds:group here as well e.g.
<xsl:apply-templates select="ds:group[not(ds:id = 'Entryway' or ds:id = 'Route')]"/>
-->
</xsl:template>
AFAICT you want to do something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://ws.wso2.org/dataservice"
exclude-result-prefixes="ns0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/ns0:document">
<Folders>
<xsl:variable name="accessible" select="ns0:group[ns0:id='Entryway' or ns0:id ='Route']" />
<xsl:if test="$accessible">
<Folder id="Accessible">
<name>Accessible Features</name>
<xsl:apply-templates select="$accessible/ns0:item"/>
</Folder>
</xsl:if>
<xsl:apply-templates select="ns0:group[not(ns0:id='Entryway' or ns0:id ='Route')]"/>
</Folders>
</xsl:template>
<xsl:template match="ns0:group">
<Folder id="{ns0:id}">
<name>
<xsl:value-of select="display_name"/>
</name>
<xsl:apply-templates select="ns0:item"/>
</Folder>
</xsl:template>
<xsl:template match="ns0:item">
<Placemark id="{ns0:id}">
<name>
<xsl:value-of select="ns0:name"/>
</name>
<!-- more here -->
</Placemark>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="/ds:document">
<kml>
<Document>
<name>Campus Map</name>
<xsl:apply-templates select="ds:group[ds:id != 'Entryway' and ds:id != 'Route']">
<xsl:sort select="ds:display_name"/>
</xsl:apply-templates>
<Folder id='Accessible'>
<name>Accessible Feature</name>
<xsl:apply-templates select="ds:group[ds:id = 'Entryway' or ds:id = 'Route']"/>
</Folder>
</Document>
</kml>
</xsl:template>
<xsl:template match="ds:group[ds:id = 'Entryway' or ds:id = 'Route']">
<xsl:apply-templates select="ds:item"/>
</xsl:template>
<xsl:template match="ds:group[ds:id != 'Entryway' and ds:id != 'Route']">
<Folder id="{ds:id}">
<name>
<xsl:value-of select="ds:display_name"/>
</name>
<xsl:apply-templates select="ds:item">
<xsl:sort select="ds:name"/>
</xsl:apply-templates>
</Folder>
</xsl:template>
I'm new to XSLT and trying to transform from XML to pipe-delimited format. The problem that I'm having is that in the output, each claim has to be duplicated for each service line.
Expected Output:
EP030315706890704|TESTSUBMITTER|FAMILY HEALTHCARE|1122334455|1|99214|179.00
EP030315706890704|TESTSUBMITTER|FAMILY HEALTHCARE|1122334455|2|2000F|0.00
EP030315706890705|TESTSUBMITTER2|FAMILY HEALTHCARE|1122334455|1|99214|179.00
EP030315706890705|TESTSUBMITTER2|FAMILY HEALTHCARE|1122334455|2|2000F|0.00
Input XML looks as follows:
<payloadContainer>
<afile>
<clm>
<hdr>
<corn>EP030315706890704</corn>
<idSend>112233445</idSend>
<nmSend>TESTSUBMITTER</nmSend>
</hdr>
<provBill>
<name>
<nmOrg>FAMILY HEALTHCARE</nmOrg>
</name>
<id T="XX" P="P">1122334455</id>
</provBill>
<serv S="1">
<numLine>1</numLine>
<prof>
<px L="S">
<cdPx T="HC">99214</cdPx>
</px>
<amtChrg>179.00</amtChrg>
</prof>
</serv>
<serv S="2">
<numLine>2</numLine>
<prof>
<px L="S">
<cdPx T="HC">2000F</cdPx>
</px>
<amtChrg>0.00</amtChrg>
</prof>
</serv>
</clm>
<clm>
<hdr>
<corn>EP030315706890705</corn>
<idSend>112233445</idSend>
<nmSend>TESTSUBMITTER2</nmSend>
</hdr>
<provBill>
<name>
<nmOrg>FAMILY HEALTHCARE</nmOrg>
</name>
<id T="XX" P="P">1122334455</id>
</provBill>
<serv S="1">
<numLine>1</numLine>
<prof>
<px L="S">
<cdPx T="HC">99214</cdPx>
</px>
<amtChrg>179.00</amtChrg>
</prof>
</serv>
<serv S="2">
<numLine>2</numLine>
<prof>
<px L="S">
<cdPx T="HC">2000F</cdPx>
</px>
<amtChrg>0.00</amtChrg>
</prof>
</serv>
</clm>
</afile>
</payloadContainer>
Desired output XML:
<Table>
<row>
.... All the fields represented here.
</row>
</Table>
Possible solution: https://www.dropbox.com/s/wzvtzw7ihtgxx9o/claimtoRedshift.xsl
This scenario creates two row's dynamically. However, I'm still stuck at how to duplicate for each service line.
I don't see the connection of the linked XSLT to the question presented here. AFAICT, the following stylesheet will return the expected pipe-delimited output:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/payloadContainer">
<xsl:for-each select="afile/clm">
<xsl:variable name="common">
<xsl:value-of select="hdr/corn"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="hdr/nmSend"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="provBill/name/nmOrg"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="provBill/id"/>
<xsl:text>|</xsl:text>
</xsl:variable>
<xsl:for-each select="serv">
<xsl:value-of select="$common"/>
<xsl:value-of select="numLine"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="prof/px/cdPx"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="prof/amtChrg"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I'm facing an issue in production which I'd like your help to understand what would be the best option of XSLT code change to fix it.
I have the following source structure that needs to be transformed inside my middleware:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:SMRESULTS xmlns:ns0="http://www.mycompany.com/SYS/SCENARIO/VERSION">
<ns0:PREAMBLE>
<ns0:I_SITE_CODE/>
<ns0:I_DESTINATION/>
<ns0:I_FILENAME/>
<ns0:I_RECORD_TYPE/>
</ns0:PREAMBLE>
<ns0:SAMPLES>
<ns0:SAMPLE>
<ns0:S_APPROVAL_REASON/>
<ns0:D_TANK_CONFORMITY/>
<ns0:D_SAMPLE>
<ns0:D_SAMPLE_ID/>
<ns0:D_SAMPLE_VALUE/>
</ns0:D_SAMPLE>
<ns0:TESTS>
<ns0:TEST>
<ns0:T_ANALYSIS/>
<ns0:T_AUTHORISATION_COMMENT/>
<ns0:D_TEST>
<ns0:D_TEST_ID/>
<ns0:D_TEST_VALUE/>
</ns0:D_TEST>
<ns0:RESULTS>
<ns0:RESULT>
<ns0:R_VALUE/>
<ns0:D_GRDB_PROPERTY/>
<ns0:D_RESULT>
<ns0:D_RESULT_ID/>
<ns0:D_RESULT_VALUE/>
</ns0:D_RESULT>
</ns0:RESULT>
</ns0:RESULTS>
</ns0:TEST>
</ns0:TESTS>
</ns0:SAMPLE>
</ns0:SAMPLES>
</ns0:SMRESULTS>
My requirement is that whenever a "<" sign is found (characteristic D_RESULT_ID = 'Sm.Result.Min_Limit' and D_RESULT_VALUE = <![CDATA[<=600.0000]]>
the value must be transferred to 'Sm.Result.Max_Limit' characteristic and the characteristic 'Sm.Result.Min_Limit' must be blanked out.
Exemplifying: For the below source data...
<?xml version="1.0" encoding="ISO-8859-1" ?>
<SMRESULTS xmlns="http://www.mycompany.com/SYS/SCENARIO/VERSION" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PREAMBLE>
<I_SITE_CODE>Site Code</I_SITE_CODE>
<I_DESTINATION>Destination</I_DESTINATION>
<I_FILENAME>filename.zzz</I_FILENAME>
<I_RECORD_TYPE>INSERT</I_RECORD_TYPE>
</PREAMBLE>
<SAMPLES>
<SAMPLE>
<S_APPROVAL_REASON></S_APPROVAL_REASON>
<D_TANK_CONFORMITY></D_TANK_CONFORMITY>
<D_SAMPLE>
<D_SAMPLE_ID>Sm.Sample.BatchId</D_SAMPLE_ID>
<D_SAMPLE_VALUE></D_SAMPLE_VALUE>
</D_SAMPLE>
<D_SAMPLE>
<D_SAMPLE_ID>Sm.Sample.Type</D_SAMPLE_ID>
<D_SAMPLE_VALUE></D_SAMPLE_VALUE>
</D_SAMPLE>
<D_SAMPLE>
<D_SAMPLE_ID>SM.Sample.Template_ID</D_SAMPLE_ID>
<D_SAMPLE_VALUE>SPEP-PE</D_SAMPLE_VALUE>
</D_SAMPLE>
<TESTS>
<TEST>
<T_ANALYSIS>AnalysisCode</T_ANALYSIS>
<D_TEST>
<D_TEST_ID>Sm.Test.DerivedGRDBTestMethod</D_TEST_ID>
<D_TEST_VALUE></D_TEST_VALUE>
</D_TEST>
<RESULTS>
<RESULT xsi:nil="false">
<R_VALUE>0.000</R_VALUE>
<D_GRDB_PROPERTY></D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
<RESULT xsi:nil="false">
<R_VALUE>0.000</R_VALUE>
<D_GRDB_PROPERTY></D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
<RESULT xsi:nil="false">
<R_VALUE>344.712</R_VALUE>
<D_GRDB_PROPERTY>ASH</D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE>59W</D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE><![CDATA[<=600.0000]]></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
</RESULTS>
</TEST>
</TESTS>
</SAMPLE>
</SAMPLES>
</SMRESULTS>
...the desired result should be as follow:
...
<RESULT>
<R_VALUE>344.712</R_VALUE>
<D_GRDB_PROPERTY>ASH</D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE>59W</D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE/>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE><![CDATA[<=600.0000]]></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
...
I have to do this adjust in the current XSLT, which is as follow:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://www.mycompany.com/SYS/SCENARIO/VERSION" xmlns:map="java:java.util.Map" xmlns:dyn="java:com.sap.aii.mapping.api.DynamicConfiguration" xmlns:key="java:com.sap.aii.mapping.api.DynamicConfigurationKey" xmlns:javamap="java:package.xi.common.util.DateConversion">
<xsl:output method="xml" encoding="ISO-8859-1" indent="yes"/>
<xsl:param name="inputparam"/>
<xsl:param name="Region">
<xsl:text>UTC</xsl:text>
</xsl:param>
<xsl:param name="DateTimeFormat">
<xsl:text>yyyyMMdd_HHmmss</xsl:text>
</xsl:param>
<xsl:param name="DYNAMIC_CONFIG_NS_FILE">
<xsl:text>http://sap.com/xi/XI/System/File</xsl:text>
</xsl:param>
<xsl:param name="DYNAMIC_CONFIG_KEY">
<xsl:text>FileName</xsl:text>
</xsl:param>
<xsl:param name="SampleID">
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:S_ID_NUMERIC"/>
</xsl:param>
<!-- Call the getCurrentDateTime function from Global Services.-->
<xsl:param name="CurrentDateTime">
<xsl:if test="function-available('javamap:getCurrentDateTime')">
<xsl:value-of select="javamap:getCurrentDateTime($Region, $DateTimeFormat)"/>
</xsl:if>
</xsl:param>
<xsl:param name="DynFileName">
<xsl:value-of select="concat($SampleID,'_',$CurrentDateTime,'.xml')"/>
</xsl:param>
<!-- Set File Name in Dynamic Configuration.-->
<xsl:variable name="DynamicConf" select="map:get($inputparam, 'DynamicConfiguration')"/>
<xsl:variable name="DynamicKey" select="key:create($DYNAMIC_CONFIG_NS_FILE, $DYNAMIC_CONFIG_KEY)"/>
<xsl:variable name="FileName" select="dyn:put($DynamicConf, $DynamicKey, $DynFileName)"/>
<xsl:template match="/">
<SMRESULTS xmlns="http://www.mycompany.com/SYS/SCENARIO/VERSION">
<PREAMBLE>
<I_SITE_CODE>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_SITE_CODE"/>
</I_SITE_CODE>
<I_DESTINATION>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_DESTINATION"/>
</I_DESTINATION>
<I_FILENAME>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_FILENAME"/>
</I_FILENAME>
<I_RECORD_TYPE>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_RECORD_TYPE"/>
</I_RECORD_TYPE>
</PREAMBLE>
<SAMPLES>
<SAMPLE>
<S_APPROVAL_REASON>
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:S_APPROVAL_REASON"/>
</S_APPROVAL_REASON>
<D_TANK_CONFORMITY>
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:D_TANK_CONFORMITY"/>
</D_TANK_CONFORMITY>
<xsl:for-each select="/a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:D_SAMPLE">
<D_SAMPLE>
<D_SAMPLE_ID>
<xsl:value-of select="a:D_SAMPLE_ID"/>
</D_SAMPLE_ID>
<D_SAMPLE_VALUE>
<xsl:value-of select="a:D_SAMPLE_VALUE"/>
</D_SAMPLE_VALUE>
</D_SAMPLE>
</xsl:for-each>
<TESTS>
<xsl:for-each select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:TESTS/a:TEST">
<TEST>
<T_ANALYSIS>
<xsl:value-of select="a:T_ANALYSIS"/>
</T_ANALYSIS>
<T_AUTHORISATION_COMMENT>
<xsl:value-of select="a:T_AUTHORISATION_COMMENT"/>
</T_AUTHORISATION_COMMENT>
<xsl:for-each select="a:D_TEST">
<D_TEST>
<D_TEST_ID>
<xsl:value-of select="a:D_TEST_ID"/>
</D_TEST_ID>
<D_TEST_VALUE>
<xsl:value-of select="a:D_TEST_VALUE"/>
</D_TEST_VALUE>
</D_TEST>
</xsl:for-each>
<RESULTS>
<xsl:for-each select="a:RESULTS/a:RESULT">
<RESULT>
<R_VALUE>
<xsl:value-of select="a:R_VALUE" disable-output-escaping="yes"/>
</R_VALUE>
<D_GRDB_PROPERTY>
<xsl:value-of select="a:D_GRDB_PROPERTY" disable-output-escaping="yes"/>
</D_GRDB_PROPERTY>
<xsl:for-each select="a:D_RESULT">
<D_RESULT>
<D_RESULT_ID>
<xsl:value-of select="a:D_RESULT_ID"/>
</D_RESULT_ID>
<D_RESULT_VALUE>
<xsl:value-of select="a:D_RESULT_VALUE"/>
</D_RESULT_VALUE>
</D_RESULT>
</xsl:for-each>
</RESULT>
</xsl:for-each>
</RESULTS>
</TEST>
</xsl:for-each>
</TESTS>
</SAMPLE>
</SAMPLES>
</SMRESULTS>
</xsl:template>
</xsl:stylesheet>
I have removed some unnecessary directly-mapped fields just to make it shorter.
Any comments/suggestions will be greatly appreciated!
Thanks!
Your existing transform is horrible. You have my sympathy.
Nevertheless, you should be able to achieve the behavior you describe by modifying the template fragment for the content of <D_RESULT_VALUE> elements, along the same lines as the solution you were offered in your other question. Here's the relevant fragment of the updated stylesheet (a little wider than the actual change, so as to make the context of the XPath expressions clear; also, dedented):
<xsl:for-each select="a:D_RESULT">
<D_RESULT>
<D_RESULT_ID>
<xsl:value-of select="a:D_RESULT_ID"/>
</D_RESULT_ID>
<D_RESULT_VALUE>
<xsl:choose>
<xsl:when test="a:D_RESULT_ID='Sm.Result.Max_Limit' and ../a:D_RESULT[a:D_RESULT_ID='Sm.Result.Min_Limit'][contains(a:D_RESULT_VALUE, '<')]">
<xsl:value-of select="../a:D_RESULT[a:D_RESULT_ID='Sm.Result.Min_Limit']/a:D_RESULT_VALUE"/>
</xsl:when>
<xsl:when test="a:D_RESULT_ID='Sm.Result.Min_Limit' and contains(., '<')"/>
<xsl:otherwise>
<xsl:value-of select="a:D_RESULT_VALUE"/>
</xsl:otherwise>
</xsl:choose>
</D_RESULT_VALUE>
</D_RESULT>
</xsl:for-each>
I don't see any way to do what you want with a smaller change.
Note that this template fragment assumes that any <RESULT> element that needs to be modified contains, in addition to a <D_RESULT> with D_RESULT_ID='Sm.Result.Min_Limit', another <D_RESULT> with D_RESULT_ID='Sm.Result.Max_Limit' into which to copy the former's <D_RESULT_VALUE>. If that is not the case then the transform will simply discard the Min_Limit value.
Moreover, when a Min_Limit value is copied to a Max_Limit, any previous value of the Max_Limit is irretrievably lost (but as far as I can tell, that's what you want).
All-
I am trying to understand the root cause for 2 nodes getting merged.
The input XML
<?xml version='1.0' encoding='UTF-8'?>
<Employees>
<Employee>
<Employee_ID>E00001</Employee_ID>
<Legal_Name Descriptor="John Doe" />
<lastName>Doe</lastName>
<firstName>John</firstName>
<P_From_Date>2015-04-01-08:00</P_From_Date>
<P_End_Date>2015-12-31-08:00</P_End_Date>
<Transaction>
<Plan Descriptor="Plan A" />
<effective_date>2015-03-22-08:00</effective_date>
<end_date>2015-10-22</end_date>
<Annual_Cost>6000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan A" />
<effective_date>2015-02-03-08:00</effective_date>
<Annual_Cost>4000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan A" />
<effective_date>2013-02-03-08:00</effective_date>
<Annual_Cost>3000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan B" />
<effective_date>2014-12-03-08:00</effective_date>
<Annual_Cost>12000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan B" />
<effective_date>2014-10-03-08:00</effective_date>
<Annual_Cost>1000</Annual_Cost>
</Transaction>
</Employee>
<Employee>
<Employee_ID>E00002</Employee_ID>
<Legal_Name Descriptor="John Doe" />
<lastName>Test</lastName>
<firstName>Jane</firstName>
<P_From_Date>2015-01-01-08:00</P_From_Date>
<Transaction>
<Plan Descriptor="Plan D" />
<effective_date>2015-05-22-08:00</effective_date>
<Annual_Cost>12000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan D" />
<effective_date>2014-03-01-08:00</effective_date>
<Annual_Cost>9000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan C" />
<effective_date>2014-12-03-08:00</effective_date>
<Annual_Cost>3000</Annual_Cost>
</Transaction>
<Transaction>
<Plan Descriptor="Plan C" />
<effective_date>2013-01-03-08:00</effective_date>
<Annual_Cost>3000</Annual_Cost>
</Transaction>
</Employee>
</Employees>
And the XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<!-- TODO customize transformation rules
syntax recommendation http://www.w3.org/TR/xslt
-->
<xsl:variable name="newline" select="'
'"/>
<xsl:variable name="delimiter">,</xsl:variable>
<xsl:variable name="qualifier">
<xsl:text>"</xsl:text>
</xsl:variable>
<xsl:template match="/Employees">
<EES>
<xsl:apply-templates/>
</EES>
</xsl:template>
<xsl:template match="Employee">
<EE>
<EID>
<xsl:value-of select="Employee_ID" />
</EID>
<FULNAME>
<xsl:value-of select="Legal_Name/#Descriptor"/>
</FULNAME>
<LNAME>
<xsl:value-of select="lastName"/>
</LNAME>
<FNAME>
<xsl:value-of select="firstName"/>
</FNAME>
<xsl:variable name="bework">
<xsl:for-each-group select="Transaction" group-by="Plan/#Descriptor" >
<berow>
<CurrentGroup>
<xsl:value-of select="current-grouping-key()"/>
</CurrentGroup>
<parm_from_date><xsl:value-of select="../P_From_Date" /></parm_from_date>
<xsl:for-each select="current-group()">
<begin-date><xsl:copy-of select="effective_date" /></begin-date>
<include-flag >
<xsl:choose>
<xsl:when test="xs:date( substring(effective_date,1,10)) >= xs:date(substring(../P_From_Date,1,10))">
<xsl:text>Y</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>N</xsl:text>
</xsl:otherwise>
</xsl:choose>
</include-flag>
<adj-begin-date>
<xsl:choose>
<xsl:when test="xs:date(effective_date) >= xs:date(../P_From_Date_1) ">
<xsl:value-of select="effective_date"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="../P_From_Date_1"/>
</xsl:otherwise>
</xsl:choose>
</adj-begin-date>
<end_date>
<xsl:value-of select="current-group()/end_date"/>
</end_date>
<Cost>
<xsl:value-of select="Annual_Cost"/>
</Cost>
</xsl:for-each>
</berow>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$bework/berow">
<CGR>
<xsl:value-of select="CurrentGroup" />
</CGR>
<PFRMDT>
<xsl:value-of select="parm_from_date" />
</PFRMDT>
<BDT>
<xsl:value-of select="begin-date" />
</BDT>
<FLAG>
<xsl:value-of select="include-flag" />
</FLAG>
<ADJBGNDT>
<xsl:value-of select="$qualifier"/>
</ADJBGNDT>
<EDATE>
<xsl:value-of select="$qualifier"/>
</EDATE>
<CO>
<xsl:value-of select="Cost" />
</CO>
</xsl:for-each>
</EE>
</xsl:template>
</xsl:stylesheet>
The result
<?xml version="1.0" encoding="UTF-8"?>
<EES xmlns:xs="http://www.w3.org/2001/XMLSchema">
<EE>
<EID>E00001</EID>
<FULNAME>John Doe</FULNAME>
<LNAME>Doe</LNAME>
<FNAME>John</FNAME>
<CGR>Plan A</CGR>
<PFRMDT>2015-04-01-08:00</PFRMDT>
<BDT>2015-03-22-08:00 2015-02-03-08:00 2013-02-03-08:00</BDT>
<FLAG>N N N</FLAG>
<ADJBGNDT>"</ADJBGNDT>
<EDATE>"</EDATE>
<CO>6000 4000 3000</CO>
<CGR>Plan B</CGR>
<PFRMDT>2015-04-01-08:00</PFRMDT>
<BDT>2014-12-03-08:00 2014-10-03-08:00</BDT>
<FLAG>N N</FLAG>
<ADJBGNDT>"</ADJBGNDT>
<EDATE>"</EDATE>
<CO>12000 1000</CO>
</EE>
<EE>
<EID>E00002</EID>
<FULNAME>John Doe</FULNAME>
<LNAME>Test</LNAME>
<FNAME>Jane</FNAME>
<CGR>Plan D</CGR>
<PFRMDT>2015-01-01-08:00</PFRMDT>
<BDT>2015-05-22-08:00 2014-03-01-08:00</BDT>
<FLAG>Y N</FLAG>
<ADJBGNDT>"</ADJBGNDT>
<EDATE>"</EDATE>
<CO>12000 9000</CO>
<CGR>Plan C</CGR>
<PFRMDT>2015-01-01-08:00</PFRMDT>
<BDT>2014-12-03-08:00 2013-01-03-08:00</BDT>
<FLAG>N N</FLAG>
<ADJBGNDT>"</ADJBGNDT>
<EDATE>"</EDATE>
<CO>3000 3000</CO>
</EE>
</EES>
If you look at John Doe's BDT node, there are 2 dates. These are 2 nodes for the sample plan are getting added to the same node despite looping through the current group.
WHat is causing this? And what should be done to remedy this? I will have to use variables as there is more manulations I will have to do. But that is for another day.
Thanks for providng me some insight.
Inside of your bework variable you create a berow element for each Transaction group but then you use <xsl:for-each select="current-group()"> to output a begin-date for each Transaction in that group, without structuring or wrapping them further. With your input that means that berow element can contain two or three begin-date elements.
Then you have <xsl:for-each select="$bework/berow"> and inside
<BDT>
<xsl:value-of select="begin-date" />
</BDT>
which will select and output the string value of the two or three begin-date elements.
I am not sure which value you want to output for BDT, you could use e.g. <xsl:value-of select="begin-date[1]"/> or <xsl:value-of select="begin-date[last()]"/> to output only the string value of the first or last element created earlier.
Perhaps you just need to change:
<BDT>
<xsl:value-of select="begin-date" />
</BDT>
to:
<BDT>
<xsl:copy-of select="begin-date" />
</BDT>
In XSLT 2.0, xsl:value-of will generate a single text node, concatenating the values of all matching nodes, separated by a space (or another separator, if specified).
Additional explanation:
WHat is causing this?
The reason why your nodes are getting merged into a single text node is that you are using xsl:value-of when you try to fetch them from the $bework variable in order to write them into the output tree.
Consider the following simplified example:
XML
<root>
<item>
<category>A</category>
<amount>1000</amount>
</item>
<item>
<category>A</category>
<amount>500</amount>
</item>
<item>
<category>A</category>
<amount>250</amount>
</item>
<item>
<category>B</category>
<amount>600</amount>
</item>
<item>
<category>B</category>
<amount>300</amount>
</item>
</root>
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:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:variable name="groups">
<xsl:for-each-group select="item" group-by="category">
<group category="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<amount>
<xsl:value-of select="amount"/>
</amount>
</xsl:for-each>
</group>
</xsl:for-each-group>
</xsl:variable>
<output>
<xsl:for-each select="$groups/group">
<group category="{#category}">
<copy-of-amount>
<xsl:copy-of select="amount"/>
</copy-of-amount>
<for-each-amount>
<xsl:for-each select="amount">
<new-node value="{.}"/>
</xsl:for-each>
</for-each-amount>
<sum-of-amount>
<xsl:value-of select="sum(amount)"/>
</sum-of-amount>
<value-of-amount>
<xsl:value-of select="amount"/>
</value-of-amount>
</group>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>
<group category="A">
<copy-of-amount>
<amount>1000</amount>
<amount>500</amount>
<amount>250</amount>
</copy-of-amount>
<for-each-amount>
<new-node value="1000"/>
<new-node value="500"/>
<new-node value="250"/>
</for-each-amount>
<sum-of-amount>1750</sum-of-amount>
<value-of-amount>1000 500 250</value-of-amount>
</group>
<group category="B">
<copy-of-amount>
<amount>600</amount>
<amount>300</amount>
</copy-of-amount>
<for-each-amount>
<new-node value="600"/>
<new-node value="300"/>
</for-each-amount>
<sum-of-amount>900</sum-of-amount>
<value-of-amount>600 300</value-of-amount>
</group>
</output>
As you can see, inside the $myVar variable, each group contains 2-3 distinct amount nodes. You can copy them, sum them or create something for each one of them. However, when you do:
<xsl:value-of select="amount"/>
you are addressing all the amount nodes in the current group, and you will get a result that incorporates them all, same as:
<xsl:value-of select="sum(amount)"/>
returns a result based on all the amount nodes being addressed.
And what should be done to remedy this?
We won't know that until you tell us what is the actual result you want to get. In the comments below you said that:
the final result is really the total cost per employee.
If so, the example above shows how to get it.
I have the following xml :
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person>
<phone type='home'>203-555-1212</phone>
<phone type='fax'>203-555-1212</phone>
<address type='home'>
<street>12 Main Street</street>
<city>Southbury</city>
<state>CT</state>
<zip>06488</zip>
</address>
<firstName>Charles</firstName>
<lastName>Smithington</lastName>
</person>
<person1>
<phone type='home'>58-99-44-999</phone>
<phone type='fax'>5788-9987-3365</phone>
<address type='home'>
<street>12 Main Street</street>
<city>Park Avenue</city>
<state>NY</state>
<zip>10025</zip>
</address>
<firstName>Mike</firstName>
<lastName>Shinoda</lastName>
</person1>
</persons>
Here i have to exclude the address field of the person whose state is CT whereas to include the address of the person whose state is NY.
<xsl:template match="persons">
<persons>
<xsl:apply-templates select="person"/>
<xsl:apply-templates select="person1"/>
</persons>
</xsl:template>
<xsl:template match="person">
<person>
<xsl:copy-of select="*[name() != 'address']"/>
<xsl:apply-templates select="address"/>
</person>
</xsl:template><xsl:template match="person1">
<person1>
<xsl:copy-of select="*[name() != 'address']"/>
<xsl:apply-templates select="address"/>
</person1>
</xsl:template>
<xsl:template match="address">
<xsl:if test="not(state='CT')">
<xsl:copy-of select="../address"/>
</xsl:if>
</xsl:template>
As you apply above transformation on provided xml then it will produce following result xml.
<person>
<phone type="home">203-555-1212</phone>
<phone type="fax">203-555-1212</phone>
<firstName>Charles</firstName>
<lastName>Smithington</lastName>
</person>
<person1>
<phone type="home">58-99-44-999</phone>
<phone type="fax">5788-9987-3365</phone>
<firstName>Mike</firstName>
<lastName>Shinoda</lastName>
<address type="home">
<street>12 Main Street</street>
<city>Park Avenue</city>
<state>NY</state>
<zip>10025</zip>
</address>
</person1>