Copy using a common key value in XSL - xslt-2.0

Here is my source xml which I am struggling to transform using XSLT 2.0.
The application that I'm working on, support XSLT 3.0.
Any help is appreciated using xslt 2.0 or xslt 3.0. Thanks
<empID> is the common key to be used for look-up.
Source XML
<?xml version="1.0" encoding="utf-8"?>
<MasterFile>
<Summary>
<Workers>
<WorkerSummary>
<EmpID>83921</EmpID>
<Name>amitzner</Name>
<Title>Executive Assistant</Title>
</WorkerSummary>
<WorkerSummary>
<EmpID>65291</EmpID>
<Name>akapoor</Name>
<Title>Senior Network Engineer</Title>
</WorkerSummary>
</Workers>
</Summary>
<Payroll>
<Employee>
<Employee_ID>83921</Employee_ID>
<Payroll_ID>80034</Payroll_ID>
<OtherIDs>27239</OtherIDs>
<OtherIDs1>27215</OtherIDs1>
</Employee>
<Employee>
<Employee_ID>65291</Employee_ID>
<Payroll_ID>85934</Payroll_ID>
<OtherIDs>23912</OtherIDs>
<OtherIDs1>29321</OtherIDs1>
</Employee>
<Employee>
<Employee_ID>87196</Employee_ID>
<Payroll_ID>86089</Payroll_ID>
<OtherIDs>67896</OtherIDs>
<OtherIDs1>37891</OtherIDs1>
</Employee>
</Payroll>
<Employees>
<Employee>
<empID>83921</empID>
<LocalJuris>NYCRes</LocalJuris>
<City>New York</City>
</Employee>
<Employee>
<empID>65291</empID>
<LocalJuris/>
<City>Houston</City>
</Employee>
<Employee>
<empID>98218</empID>
<LocalJuris/>
<City>Boston</City>
</Employee>
<Employee>
<empID>87196</empID>
<LocalJuris>NYCRes</LocalJuris>
<City>Dallas</City>
</Employee>
</Employees>
</MasterFile>
Expected Output
<?xml version="1.0" encoding="UTF-8"?>
<MasterFile>
<Employees>
<Employee>
<empID>83921</empID>
<LocalJuris>NYCRes</LocalJuris>
<City>New York</City>
<Name>amitzner</Name> <!-- This needs to be copied from Summary/Workers -->
<Title>Executive Assistant</Title> <!-- This needs to be copied from Summary/Workers -->
<Payroll_ID>80034</Payroll_ID><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs>27239</OtherIDs><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs1>27215</OtherIDs1><!-- This needs to be copied from Payroll/Employee -->
</Employee>
<Employee>
<empID>65291</empID>
<LocalJuris/>
<City>Houston</City>
<Name>akapoor</Name><!-- This needs to be copied from Summary/Workers -->
<Title>Senior Network Engineer</Title> <!-- This needs to be copied from Summary/Workers -->
<Payroll_ID>85934</Payroll_ID><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs>23912</OtherIDs><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs1>29321</OtherIDs1><!-- This needs to be copied from Payroll/Employee -->
</Employee>
<Employee>
<empID>98218</empID>
<LocalJuris/>
<City>Boston</City>
</Employee>
<Employee>
<empID>87196</empID>
<LocalJuris>NYCRes</LocalJuris>
<City>Dallas</City>
<Payroll_ID>86089</Payroll_ID><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs>67896</OtherIDs><!-- This needs to be copied from Payroll/Employee -->
<OtherIDs1>37891</OtherIDs1><!-- This needs to be copied from Payroll/Employee -->
</Employee>
</Employees>
</MasterFile>
I'm able to copy some of the nodes but having hard time getting the output that I expect to produce with below XSLT
<?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 omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="LocalJuris">
<xsl:copy-of select="."/>
<Name>
<xsl:for-each select="../../../../MasterFile/Summary/Workers/WorkerSummary">
<xsl:value-of select="Name"/>
</xsl:for-each>
</Name>
</xsl:template>
<xsl:template match="Summary|Payroll">
</xsl:template>
</xsl:stylesheet>
I tried using xsl:key as suggested by Martin Honnen which returns following.
Could anyone please help me figure out what i am missing ?
<?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 omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="emp" match="Summary/Workers/WorkerSummary" use="EmpID"/>
<xsl:key name="emp" match="Payroll/Employee" use="Employee_ID"/>
<xsl:template match="EmpID">
<xsl:copy select="key('emp', empID)!(Name, Title, Payroll_ID, OtherIDs, OtherIDs1)"/>
</xsl:template>
<xsl:template match="Summary|Payroll">
</xsl:template>
</xsl:stylesheet>

Use e.g.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:key name="emp" match="Summary/Workers/WorkerSummary" use="EmpID"/>
<xsl:key name="emp" match="Payroll/Employee" use="Employee_ID"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Payroll | Summary"/>
<xsl:template match="Employee">
<xsl:copy>
<xsl:apply-templates select="node(), key('emp', empID)!(Name, Title, Payroll_ID, OtherIDs, OtherIDs1)"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
</xsl:stylesheet>
Online sample is at this link.

Related

Creating xsl:result-document with xpath 3.1 fn:transform using saxon 9.9 EE

I'd like to create an output document using the xpath 3.1 fn:transform. Following is A.xsl. It creates A.xml when run directly (from oxygen):
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output name="xml" method="xml" indent="true" />
<xsl:template name="xsl:initial-template">
<xsl:message select="'A'"/>
<xsl:result-document href="file:/C:/Work/test/A.xml" format="xml">
<resultDoc>
<text>The result of A.</text>
</resultDoc>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
Result: A.xml is created with the desired output:
<?xml version="1.0" encoding="UTF-8"?>
<resultDoc>
<text>The result of A.</text>
</resultDoc>
Now, using the transform function to call A.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="3.0">
<xsl:output name="xml" method="xml" encoding="UTF-8" indent="true" />
<!-- Global Constants -->
<xsl:variable name="xsl-file-base" select="'file:/C:/Work/test/'" as="xs:string"/>
<xsl:variable name="xsl-pipeline" select="'A.xsl'" as="xs:string"/>
<!-- Entry Point -->
<xsl:template name="xsl:initial-template">
<xsl:iterate select="$xsl-pipeline">
<xsl:variable name="file" select="$xsl-file-base || ." as="xs:string"/>
<xsl:result-document href="file:/C:/Work/test/A.xml" format="xml">
<xsl:sequence select="transform(map{'stylesheet-location' : $file})?output"/>
</xsl:result-document>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
Result: A.xml is created but incomplete. Any help is appreciated.
<?xml version="1.0" encoding="UTF-8"?>
The result of the transform function is a map with an entry named output for the primary result document and further entries for secondary result documents. Your called stylesheet creates a secondary result with the URI file:/C:/Work/test/A.xml so
<xsl:sequence
select="transform(map{'stylesheet-location' : $file})('file:/C:/Work/test/A.xml')"/>
is more likely to produce an output.

How can we remove blank line without strip-space and indent XSLT2.0

I am trying remove blank lines without stripping spaces and indentation, because my requirement is indented XML. Can anyone help me, please?
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<Export>
<bio id="b0001">
<p>Maciej</p>
</bio>
<funding-group>
<award-group>
<funding-source>
<named-content content-type="funder-name">Narodowe</named-content>
<named-content content-type="funderidentifier">501100004281</named-content>
</funding-source>
<award-id>/19/B/HS4/</award-id>
<award-id>3</award-id>
</award-group>
</funding-group>
</Export>
Expected Result
<?xml version="1.0" encoding="UTF-8"?>
<Export>
<bio id="b0001">
<p>Maciej</p>
</bio>
<funding-group>
<award-group>
<funding-source>
<named-content content-type="funder-name">Narodowe Centrum Nauki</named-content>
<named-content content-type="funderidentifier">10.13039/501100004281</named-content>
</funding-source>
<award-id>/19/B/HS4/</award-id>
<award-id>3</award-id>
</award-group>
</funding-group>
</Export>
XSLT I have tried this xsl but it's not worked properly if i have run this xsl then generate XML single line.
<?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="no"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//text()">
<xsl:value-of select="translate(.,'
', '')"/>
</xsl:template>
</xsl:stylesheet>

XSLT on XML Get parent Value from a mixed Node

I have an XML with some mixed Nodes,and I want to get just the value of the parent and not the child.
My XML
<?xml version="1.0" encoding="UTF-8"?>
<Records>
<DET>
<detnumber>100126</detnumber>
<EmployeeNo>100126</EmployeeNo>
<action>CHANGE</action>
<first_name> NewHire-4th
<previous>NewHire</previous>
</first_name>
<last_name>Test-Changed 4th
<previous>Test-Changed 3rd</previous>
</last_name>
<birth_name>
NewHire-Changed 4th
<previous>NewHire-Changed 3rd</previous>
</birth_name>
<formal_name>
NewHire-4th Test-Changed 4th
<previous>NewHire Test-Changed 3rd</previous>
</formal_name>
<salutation>
MISS
<previous>MRS</previous>
</salutation>
<email_address>
testHire4#gmail.com
<previous>testHire2#gmail.com</previous>
</email_address>
</DET>
</Records>
Using XSLT 2.0 ,
I am mostly using copy of in my xslt, But the whole Node and its child are being copied. I need to be able to restrict only to the parent.
<xsl:copy-of select="first_name"/>
<xsl:copy-of select="last_name"/>
<xsl:copy-of select="birth_name"/>
<xsl:copy-of select="formal_name"/>
<xsl:copy-of select="salutation"/>
Below is my preferred output
<?xml version="1.0" encoding="UTF-8"?>
<Records>
<DET>
<detnumber>100126</detnumber>
<EmployeeNo>100126</EmployeeNo>
<action>CHANGE</action>
<first_name> NewHire-4th</first_name>
<last_name>Test-Changed 4th</last_name>
<birth_name>NewHire-Changed 4th</birth_name>
<formal_name>NewHire-4th Test-Changed 4th</formal_name>
<salutation>MISS</salutation>
<email_address>testHire4#gmail.com</email_address>
</DET>
</Records>
Check this Code:-
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="previous"/>
</xsl:stylesheet>

XSLT to remove milliseconds from timestamp

I am attempting to write an XSLT stylesheet that removes the milliseconds from any timestamp in an XML form. My sample XML below is just a sample there could conceivably be any number of timestamps in the envelope. So I'm thinking I need to pattern match the timestamp and then transform it. I can use XSLT 2.0 The original message looks like:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
</soap:Header>
<soap:Body>
<Staging_Submit_Service xmlns="com.xxx">
<u_From_Partner__c>Our Partner</u_From_Partner__c>
<u_To_Partner__c>Us</u_To_Partner__c>
<u_Partner_CI__c/>
<u_Partner_ID__c>10051</u_Partner_ID__c>
<u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
<u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c>
<u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
<u_Partner_Submit_Date__c>2016-07-25T18:11:23.5443Z</u_Partner_Submit_Date__c>
<u_Partner_Priority__c>Low</u_Partner_Priority__c>
<u_Partner_Service_Type>Event</u_Partner_Service_Type>
</Staging_Submit_Service>
</soap:Body>
</soap:Envelope>
and my resulting xml needs to look like:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
</soap:Header><soap:Body>
<Staging_Submit_Service xmlns="com.xxx">
<u_From_Partner__c>Our Partner</u_From_Partner__c>
<u_To_Partner__c>Us</u_To_Partner__c>
<u_Partner_CI__c/>
<u_Partner_ID__c>10051</u_Partner_ID__c>
<u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
<u_Partner_Reported_Date__c>2016-07-26T17:38:28Z</u_Partner_Reported_Date__c>
<u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
<u_Partner_Submit_Date__c>2016-07-25T18:11:23Z</u_Partner_Submit_Date__c>
<u_Partner_Priority__c>Low</u_Partner_Priority__c>
<u_Partner_Service_Type>Event</u_Partner_Service_Type>
</Staging_Submit_Service>
</soap:Body>
</soap:Envelope>
Notice the timestamps. I started down this path but it doesn't seem to be getting me where I need to be.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="java:com.verizon.webservices.adapter.clecclient">
<xsl:output method="xml" indent="no" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()"
<xsl:copy>
<xsl:value-of select="." />
<xsl:value-of select='matches(.,".*[0-9]\{4\}-[0-9]\{2\}.*:[0-9]\{2\}*")'/>
<xsl:value-of select='replace(., "s/.*[0-9]\{4\}-[0-9]\{2\}.*:[0-9]\{2\}\(\.[0-9]*\).*/\1","")'/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I am really only vaguely familiar with XSLT and this particular problem requires me to use it.
From the comments it seems that you can only use an XSLT 1.0 solution.
Here is one:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:df="com.xxx">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="df:u_Partner_Reported_Date__c/text()
|df:u_Partner_Submit_Date__c/text()">
<xsl:value-of select="concat(substring-before(.,'.'), 'Z')"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
</soap:Header>
<soap:Body>
<Staging_Submit_Service xmlns="com.xxx">
<u_From_Partner__c>Our Partner</u_From_Partner__c>
<u_To_Partner__c>Us</u_To_Partner__c>
<u_Partner_CI__c/>
<u_Partner_ID__c>10051</u_Partner_ID__c>
<u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
<u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c>
<u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
<u_Partner_Submit_Date__c>2016-07-25T18:11:23.5443Z</u_Partner_Submit_Date__c>
<u_Partner_Priority__c>Low</u_Partner_Priority__c>
<u_Partner_Service_Type>Event</u_Partner_Service_Type>
</Staging_Submit_Service>
</soap:Body>
</soap:Envelope>
the wanted, correct result is produced:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
</soap:Header>
<soap:Body>
<Staging_Submit_Service xmlns="com.xxx">
<u_From_Partner__c>Our Partner</u_From_Partner__c>
<u_To_Partner__c>Us</u_To_Partner__c>
<u_Partner_CI__c/>
<u_Partner_ID__c>10051</u_Partner_ID__c>
<u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
<u_Partner_Reported_Date__c>2016-07-26T17:38:28Z</u_Partner_Reported_Date__c>
<u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
<u_Partner_Submit_Date__c>2016-07-25T18:11:23Z</u_Partner_Submit_Date__c>
<u_Partner_Priority__c>Low</u_Partner_Priority__c>
<u_Partner_Service_Type>Event</u_Partner_Service_Type>
</Staging_Submit_Service>
</soap:Body>
</soap:Envelope>
Try
<xsl:template match="*[not(*) and . castable as xs:dateTime]">
<xsl:copy>
<xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')"/>
</xsl:copy>
</xsl:template>
plus your first template.
So the complete stylesheet is
<?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:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and . castable as xs:dateTime]">
<xsl:copy>
<xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Actually the above seems to not preserve any timezone suffix present and ensuring it is output as Z if it is UTC is a bit tricky, but I think if you make the value-of
<xsl:value-of select="if (timezone-from-dateTime(.) eq xs:dayTimeDuration('PT0H')) then format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]Z') else format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z]')"/>
then it works fine.
It seems the problem about the timezone Z was resolved in https://www.w3.org/TR/xpath-functions-31/#rules-for-datetime-formatting to allow
<xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z00:00t]')"/>
but I have not tested whether that works with XmlPrime or processors other than Saxon.
The following works for me with Xalan inside Oxygen as far as identifying the two elements with dateTimes in your input sample and reformatting them to remove the decimals of the seconds:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:date="http://exslt.org/dates-and-times"
exclude-result-prefixes="xs date" version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and string-length() > 19 and date:date() != '']">
<xsl:copy>
<xsl:value-of select="date:format-date(date:date(.), "yyyy-MM-dd'T'HH:mm:ssZ")"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However the created output dates differ, the input <u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c> shows up as <u_Partner_Reported_Date__c>2016-07-25T22:00:00+0000</u_Partner_Reported_Date__c>, so either the date parsing or formatting is broken.

parsing with XSLT

I am struggling a bit with a solution for the following problem and was hoping someone could point me in the right direction.
To illustrate the issue I will try and pair it down to its most simple form. I have the following data:
<?xml version="1.0" encoding="UTF-8"?>
<SampleData>
<Data>AA-BRAND1,BB-BRAND1,AA-BRAND2</Data>
</SampleData>
and need to produce the following output:
<?xml version="1.0" encoding="UTF-8"?>
<ListOfBrandSales>
<BrandSales>
<BrandChannel>AA</BrandChannel>
<ListOfBrand>
<Brand>BRAND1</Brand>
<Brand>BRAND2</Brand>
</ListOfBrand>
</BrandSales>
<BrandSales>
<BrandChannel>BB</BrandChannel>
<Brand>BRAND1</Brand>
</BrandSales>
</ListOfBrandSales>
I have been playing with the tokenize and distinct-values functions but am unable to get it. Seems like I need to nest these functions and not sure if it is possible. My apologies if the solution is obvious but I am a bit new to XSLT.
Thanks in advance.
How about:
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:variable name="tokens" select="tokenize(/SampleData/Data, ',')" />
<xsl:variable name="channels">
<xsl:for-each select="$tokens">
<channel><xsl:value-of select="substring-before(., '-')"/></channel>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<ListOfBrandSales>
<xsl:for-each select="distinct-values($channels/channel)">
<BrandSales>
<BrandChannel><xsl:value-of select="."/></BrandChannel>
<ListOfBrand>
<xsl:for-each select="$tokens[starts-with(., current())]">
<Brand><xsl:value-of select="substring-after(., '-')"/></Brand>
</xsl:for-each>
</ListOfBrand>
</BrandSales>
</xsl:for-each>
</ListOfBrandSales>
</xsl:template>
</xsl:stylesheet>
Or, if you prefer:
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="/">
<ListOfBrandSales>
<xsl:for-each-group select="tokenize(SampleData/Data, ',')" group-by="substring-before(., '-')">
<BrandSales>
<BrandChannel><xsl:value-of select="current-grouping-key()"/></BrandChannel>
<ListOfBrand>
<xsl:for-each select="current-group()">
<Brand><xsl:value-of select="substring-after(., '-')"/></Brand>
</xsl:for-each>
</ListOfBrand>
</BrandSales>
</xsl:for-each-group>
</ListOfBrandSales>
</xsl:template>
</xsl:stylesheet>

Resources