I am trying to remove nodes from an xml if certain attribute values are not matching. Here is my XML:
<CONFIGURATIONS>
<CONFIG1 DOMAIN="CAE" FOCUS="IN" STATUS="ACTIVE" >
<ATTR>1<ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="INACTIVE" >
<ATTR>2<ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="ACTIVE" >
<ATTR>2<ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="MFG" FOCUS="OUT" STATUS="ACTIVE" >
<ATTR>3<ATTR>
</CONFIG1>
</CONFIGURATIONS>
I want to remove the nodes not do not have the DOMAIN value as CAE and the FOCUS is not OUT and the STATUS is not ACTIVE.
<CONFIGURATIONS>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="ACTIVE" >
<ATTR>2<ATTR>
</CONFIG1>
I am using the following xslt:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SM_CONFIG_ITEM [#DOMAIN !='CAE' and #FOCUS !='OUT' and #STATUS != 'INACTIVE']"/>
</xsl:stylesheet>
But it is not producing the desired output. What am I doing wrong?
<xsl:template match="SM_CONFIG_ITEM [#DOMAIN !='CAE' and #FOCUS !='OUT' and #STATUS != 'INACTIVE']"/>
But it is not producing the desired output. What am I doing wrong?
You want the element to be matched when one of the != conditions is satisfied -- but the above match pattern specifies that all of the != conditions must be satisfied.
Solution:
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"CONFIG1[not(#DOMAIN='CAE' and #FOCUS='OUT' and #STATUS='ACTIVE')]"/>
</xsl:stylesheet>
when applied on the provided XML document:
<CONFIGURATIONS>
<CONFIG1 DOMAIN="CAE" FOCUS="IN" STATUS="ACTIVE" >
<ATTR>1</ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="INACTIVE" >
<ATTR>2</ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="ACTIVE" >
<ATTR>2</ATTR>
</CONFIG1>
<CONFIG1 DOMAIN="MFG" FOCUS="OUT" STATUS="ACTIVE" >
<ATTR>3</ATTR>
</CONFIG1>
</CONFIGURATIONS>
produces the wanted, correct result:
<CONFIGURATIONS>
<CONFIG1 DOMAIN="CAE" FOCUS="OUT" STATUS="ACTIVE">
<ATTR>2</ATTR>
</CONFIG1>
</CONFIGURATIONS>
Related
I updated the provided xslt to accept a param "multiplexpaths" from my source and assignin enter code here`g this to nodes variable in xslt to below:
<?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="#all"
version="3.0">
<xsl:param name="multiplexpaths" as="xs:string" static="yes" />
<!-- xsl:param name="copy" as="xs:string" static="yes" select="'//other[. = 1345], //more[. = 2]'"/-->
<xsl:variable name="nodes" _select="{$multiplexpaths}"/>
<xsl:variable name="ancestors" select="$nodes/ancestor::*"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="$nodes">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template match="$ancestors">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
For the xsl:evaluate example, you would need to use Saxon 10 HE, 9.9 HE doesn't support xsl:evaluate.
As for setting a static parameter with Saxon 9.9 and s9api, a simple example is
String paths = "catalog/cd1,catalog/Test/value/a1";
Processor processor = new Processor(true);
XsltCompiler xsltCompiler = processor.newXsltCompiler();
xsltCompiler.setParameter(new QName("copy"), new XdmAtomicValue(paths));
XsltExecutable xsltExecutable = xsltCompiler.compile(new StreamSource("static-param-example2.xsl"));
Xslt30Transformer xslt30Transformer = xsltExecutable.load30();
xslt30Transformer.transform(new StreamSource("input-sample1.xml"), xslt30Transformer.newSerializer(System.out));
with the input-sample1.xml being
<catalog>
<cd1>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd1>
<cd2>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd2>
<Test>
<value>
<a1>123</a1>
<b1>77474</b1>
</value>
</Test>
</catalog>
and the XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="copy" as="xs:string" static="yes" select="'()'"/>
<xsl:variable name="nodes" _select="{$copy}"/>
<xsl:variable name="ancestors" select="$nodes/ancestor::*"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="$nodes">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template match="$ancestors">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
this outputs
<catalog>
<cd1>
<name>abc</name>
<Stext>1234</Stext>
<Tag>uuuu</Tag>
</cd1>
<Test>
<value>
<a1>123</a1>
</value>
</Test>
</catalog>
So the main point is to set the parameter on the XsltCompiler and not after compilation on the transformer.
I want to remove namespace at output structure. I prepared XSLT code
but it gives namespace on this element
My Input XML is this.
<?xml version='1.0' encoding='UTF-8'?>
<n0:Messages xmlns:n0="http://sap.com/xi/XI">
<n0:Message>
<ContactData>
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
</n0:Message>
</n0:Messages>
XSLT CODE implemented
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:n0="http://sap.com/xi/XI" exclude-result-prefixes="n0">
<!-- Output -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select= "//ContactData"/>
</xsl:template>
<xsl:template match="//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Present output:
<?xml version='1.0' encoding='UTF-8'?>
<ContactData xmlns:n0="http://sap.com/xi/XI">
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
Output expected
<?xml version='1.0' encoding='UTF-8'?>
<ContactData>
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
Please help on this code
Thank you very much.
If you're able to use XSLT 2.0, you can achieve the required output simply by:
<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="/">
<xsl:copy-of select="*/*/*" copy-namespaces="no"/>
</xsl:template>
</xsl:stylesheet>
Demo: https://xsltfiddle.liberty-development.net/3NSSEuK
In XSLT 1.0, it takes a bit more work:
<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:template match="/">
<xsl:apply-templates select="*/*/*" />
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Demo: https://xsltfiddle.liberty-development.net/3NSSEuK/1
Try this by using template * and # :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:n0="http://sap.com/xi/XI"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs math n0" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="/*:Messages/ContactData"/>
</xsl:template>
</xsl:stylesheet>
I'm new to XSL and i'm trying to copy a node of XML to another node in the same XML using XSLT. I can able to transform the file as expected but the XMLNS attribute is getting added to the destination which I don't want.
I have tried all the option of copy-namespaces='no' using XSLT2.0 but that doesn't work. Also, I cant have a prefix of namespaces in the XSLT and use exclude namespaces to avoid xmlns because the incoming XML file is dynamic and namespaces keep on changing. I can't have all the namespaces declared as a prefix in XSLT.
Incoming XML:
<?xml version="1.0" encoding="UTF-8"?>
<PropertySet>
<Message>
<NotificationHeader>
<BusinessId></BusinessId>
<CorrelationId>0201201916:21:24CKG3N</CorrelationId>
<SourceName></SourceName>
<SourceId></SourceId>
<EventType></EventType>
<SecurityIdentifierId></SecurityIdentifierId>
<ClientRequestId></ClientRequestId>
<TargetId>ESB</TargetId>
<EventTime></EventTime>
<RequestUser></RequestUser>
</NotificationHeader>
<EventList>
<Event>
<PayLoad>
<ListOfActionIo xmlns="http://www.test.com/IO">
<Action>
<ActivityId>4-309C7WV</ActivityId>
<ActivitySRId></ActivitySRId>
<ActivityTemplateId></ActivityTemplateId>
<ActivityUID>4-309C7WV</ActivityUID>
<Category> Notification</Category>
<Comment></Comment>
<Type>Action</Type>
<ListOfDestination>
<Destination>
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
<Destination>
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
</ListOfDestination>
</Action>
</ListOfActionIo>
</PayLoad>
</Event>
</EventList>
<DestinationList>
<Destination>
<DestinationName></DestinationName>
<DestinationId></DestinationId>
</Destination>
</DestinationList>
</Message>
</PropertySet>
XSLT Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[name()='Message']/*[name()='DestinationList']//*[name()='Destination']"></xsl:template>
<!--Copy the destination from one node to another node-->
<xsl:template match="//*[name()='Message']/*[name()='DestinationList']">
<xsl:copy>
<xsl:copy-of select="//*[name()='Message']/*[name()='EventList']//*[name()='Destination']"/>
</xsl:copy>
</xsl:template>
<!--Remove the original node from where the destination was copied-->
<xsl:template match="//*[name()='Message']/*[name()='EventList']//*[name()='ListOfDestination']"></xsl:template>
</xsl:stylesheet>
Output:
<PropertySet>
<Message>
<NotificationHeader>
<BusinessId/>
<CorrelationId>0201201916:21:24CKG3N</CorrelationId>
<SourceName/>
<SourceId/>
<EventType/>
<SecurityIdentifierId/>
<ClientRequestId/>
<TargetId>ESB</TargetId>
<EventTime/>
<RequestUser/>
</NotificationHeader>
<EventList>
<Event>
<PayLoad>
<ListOfActionIo xmlns="http://www.test.com/IO">
<Action>
<ActivityId>4-309C7WV</ActivityId>
<ActivitySRId/>
<ActivityTemplateId/>
<ActivityUID>4-309C7WV</ActivityUID>
<Category> Notification</Category>
<Comment/>
<Type>Action</Type>
</Action>
</ListOfActionIo>
</PayLoad>
</Event>
</EventList>
<DestinationList>
<Destination xmlns="http://www.test.com/IO">
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
<Destination xmlns="http://www.test.com/IO">
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
</DestinationList>
</Message>
</PropertySet>
Expected Output:
Without the Namespaces on the copied node.
<PropertySet>
<Message>
<NotificationHeader>
<BusinessId/>
<CorrelationId>0201201916:21:24CKG3N</CorrelationId>
<SourceName/>
<SourceId/>
<EventType/>
<SecurityIdentifierId/>
<ClientRequestId/>
<TargetId>ESB</TargetId>
<EventTime/>
<RequestUser/>
</NotificationHeader>
<EventList>
<Event>
<PayLoad>
<ListOfActionIo xmlns="http://www.test.com/IO">
<Action>
<ActivityId>4-309C7WV</ActivityId>
<ActivitySRId/>
<ActivityTemplateId/>
<ActivityUID>4-309C7WV</ActivityUID>
<Category> Notification</Category>
<Comment/>
<Type>Action</Type>
</Action>
</ListOfActionIo>
</PayLoad>
</Event>
</EventList>
<DestinationList>
<Destination>
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
<Destination>
<DestinationName>NSW Aboriginal Education Consultative Group Incorporated</DestinationName>
</Destination>
</DestinationList>
</Message>
</PropertySet>
You are asking the wrong question. You don't want to "remove namespaces" - you want to change the namespace of transformed elements. This is akin to renaming the elements.
Now, since your example is confusing (and too long), consider the following:
XML
<root>
<colors>
<color>red</color>
<color>blue</color>
</colors>
<shapes xmlns="some-unknown-namespace">
<shape>circle</shape>
<shape>square</shape>
</shapes>
<sizes>
<size>small</size>
<size>large</size>
</sizes>
</root>
To change the namespace of shapes (and its descendants, that inherit it!) to no-namespace, without knowing in advance what the original namespace will be, you can do:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor-or-self::*[name()='shapes']]">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<colors>
<color>red</color>
<color>blue</color>
</colors>
<shapes>
<shape>circle</shape>
<shape>square</shape>
</shapes>
<sizes>
<size>small</size>
<size>large</size>
</sizes>
</root>
Added:
lets modify the code to move the shapes into sizes and remove the shapes node.
OK, let's do that:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sizes">
<xsl:copy>
<xsl:apply-templates/>
<!-- move the shapes into sizes -->
<xsl:apply-templates select="../*[name()='shapes']/*"/>
</xsl:copy>
</xsl:template>
<!-- remove the shapes element -->
<xsl:template match="*[name()='shapes']"/>
<xsl:template match="*[ancestor::*[name()='shapes']]">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<colors>
<color>red</color>
<color>blue</color>
</colors>
<sizes>
<size>small</size>
<size>large</size>
<shape>circle</shape>
<shape>square</shape>
</sizes>
</root>
For a SAP PO xsl 1.0 mapping I need to map an 'exotic' file coming from our warehouse where I need to group/sum per order (RECH) a QTY field on a combination of a line identifier (MASTER_PO_LINE_NO) and an Itemnumber (SKU). Each line (RECL) is in a header (RECH).
INPUT:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Messages xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge">
<ns0:Message1>
<MARCXML>
<RCIC>
<RECH>
<SALESID>24000</SALESID>
<RECL>
<LINE_NO>1</LINE_NO>
<QTY_EXPE>1592</QTY_EXPE>
<SKU>11207-210</SKU>
<MASTER_PO_LINE_NO>10</MASTER_PO_LINE_NO>
</RECL>
<RECL>
<LINE_NO>2</LINE_NO>
<QTY_EXPE>1000</QTY_EXPE>
<SKU>11207-210</SKU>
<MASTER_PO_LINE_NO>10</MASTER_PO_LINE_NO>
</RECL>
<RECL>
<LINE_NO>3</LINE_NO>
<QTY_EXPE>175</QTY_EXPE>
<SKU>11207-210</SKU>
<MASTER_PO_LINE_NO>20</MASTER_PO_LINE_NO>
</RECL>
</RECH>
<RECH>
<SALESID>25001</SALESID>
<RECL>
<LINE_NO>1</LINE_NO>
<QTY_EXPE>440</QTY_EXPE>
<SKU>20000-210</SKU>
<MASTER_PO_LINE_NO>10</MASTER_PO_LINE_NO>
</RECL>
</RECH>
</RCIC>
</MARCXML>
</ns0:Message1>
</ns0:Messages>
Required OUTPUT (Qty for 11207-210 = 1592 + 1000):
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Messages xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge">
<ns0:Message1>
<MARCXML>
<RCIC>
<RECH>
<SALESID>24000</SALESID>
<RECL>
<LINE_NO>1</LINE_NO>
<QTY_EXPE>2592</QTY_EXPE>
<SKU>11207-210</SKU>
<MASTER_PO_LINE_NO>10</MASTER_PO_LINE_NO>
</RECL>
<RECL>
<LINE_NO>3</LINE_NO>
<QTY_EXPE>175</QTY_EXPE>
<SKU>11207-210</SKU>
<MASTER_PO_LINE_NO>20</MASTER_PO_LINE_NO>
</RECL>
</RECH>
<RECH>
<SALESID>25001</SALESID>
<RECL>
<LINE_NO>1</LINE_NO>
<QTY_EXPE>440</QTY_EXPE>
<SKU>20000-210</SKU>
<MASTER_PO_LINE_NO>10</MASTER_PO_LINE_NO>
</RECL>
</RECH>
</RCIC>
</MARCXML>
</ns0:Message1>
</ns0:Messages>
There are plenty of examples about muenchian grouping but I didn't manage to solve my requirement yet. To be honest I got as far as:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Messages xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge">
<ns0:Message1>
<MARCXML>
<RCIC>
<RECH>5284</RECH>
<RECH>5284</RECH>
<RECH>5284</RECH>
</RCIC>
</MARCXML>
</ns0:Message1>
</ns0:Messages>
With the following xsl:
<?xml version="1.0" encoding="UTF-8"?>
<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="kMSTR_PO_LN_SKU" match="RECL"
use="concat(MASTER_PO_LINE_NO, '#', SKU)"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="RECH">
<xsl:copy>
<xsl:value-of select="sum(//MARCXML/RCIC/RECH/RECL/QTY_CHECKED_IN)" />
<xsl:for-each select="/RECL[generate-id()=generate-id(key('kMSTR_PO_LN_SKU',concat(MASTER_PO_LINE_NO,'-',SKU))[1])]">
<xsl:copy>
<SKU>
<xsl:value-of select="SKU"/>
</SKU>
<Quantity>
<xsl:value-of select="sum(key('kMSTR_PO_LN_SKU',concat(MASTER_PO_LINE_NO,'-',RECL))/QTY_EXPE)"/>
</Quantity>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Hope someone can help me on my way here
AFAICT, this produces the required output - but having only a single example with somewhat ambiguous rules it could be a coincidence. In any case, it should provide you with a starting point.
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="k1" match="RECL" use="concat(MASTER_PO_LINE_NO, '|', SKU)"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="RECH">
<xsl:copy>
<xsl:copy-of select="SALESID"/>
<xsl:for-each select="RECL[generate-id()=generate-id(key('k1', concat(MASTER_PO_LINE_NO,'|',SKU))[1])]">
<xsl:copy>
<xsl:copy-of select="LINE_NO"/>
<QTY_EXPE>
<xsl:value-of select="sum(key('k1', concat(MASTER_PO_LINE_NO,'|',SKU))/QTY_EXPE)" />
</QTY_EXPE>
<xsl:copy-of select="SKU | MASTER_PO_LINE_NO"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Added:
In order to summarize every order (RECH) separately, you must add an identifier of the order to the key:
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="k1" match="RECL" use="concat(MASTER_PO_LINE_NO, '|', SKU, '|', generate-id(..))"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="RECH">
<xsl:copy>
<xsl:copy-of select="SALESID"/>
<xsl:for-each select="RECL[generate-id()=generate-id(key('k1', concat(MASTER_PO_LINE_NO,'|',SKU, '|', generate-id(..)))[1])]">
<xsl:copy>
<xsl:copy-of select="LINE_NO"/>
<QTY_EXPE>
<xsl:value-of select="sum(key('k1', concat(MASTER_PO_LINE_NO,'|',SKU, '|', generate-id(..)))/QTY_EXPE)" />
</QTY_EXPE>
<xsl:copy-of select="SKU | MASTER_PO_LINE_NO"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I need to group the records based on OPERATION_CODE. Each record can have more than one Allowance in combination tag. If more than one record have same operation_code, I need all the allowance together. I am using xsl 1.0.
Using this xsl, I am getting only one Allowance per record(in the sample input, first allowance in the first record and first allowance in the second record). The expected output is all the allowances in the first record and second record, as operation_code is same.`
sample input:
<root xmlns="">
<records>
<record>
<OPERATION_CODE>123456</OPERATION_CODE>
<Combinations>
<allowance>
<WMI_CODE>MR0</WMI_CODE>
<VDS_CODE>1</VDS_CODE>
</allowance>
<allowance>
<WMI_CODE>MR1</WMI_CODE>
<VDS_CODE>2</VDS_CODE>
</allowance>
</Combinations>
</record>
<record>
<OPERATION_CODE>123456</OPERATION_CODE>
<Combinations>
<allowance>
<WMI_CODE>MR2</WMI_CODE>
<VDS_CODE>3</VDS_CODE>
</allowance>
</Combinations>
</record>
</records>
</root>
expected output :
<LaborOperationsDetail>
<LaborOperationID>123456</LaborOperationID>
<Combinations>
<Allowance>
<GroupID>MR0</star:GroupID>
<VID>1</star:VID>
</Allowance>
<Allowance>
<GroupID>MR1</star:GroupID>
<VID>2</star:VID>
</Allowance>
<Allowance>
<GroupID>MR2</star:GroupID>
<VID>3</star:VID>
</Allowance>
</Combinations>
<LaborOperationsDetail>
xsl used :
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:key name="opcode" match="record" use="OPERATION_CODE" />
<xsl:template match="root/records">
<xsl:for-each select="record[generate-id() = generate-id(key('opcode', OPERATION_CODE)[1])]">
<LaborOperationsDetail>
<LaborOperationID><xsl:value-of select="OPERATION_CODE"/></LaborOperationID>
<Combinations>
<xsl:for-each select="key('opcode' ,OPERATION_CODE)">
<Allowance>
<GroupID><xsl:value-of select="Combinations/allowance/WMI_CODE" /></GroupID>
<VID><xsl:value-of select="Combinations/allowance/VDS_CODE" /></VID>
</Allowance>
</xsl:for-each >
</Combinations>
</LaborOperationsDetail>
</xsl:for-each >
</xsl:template>
</xsl:stylesheet>
Try it this way?
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:key name="opcode" match="record" use="OPERATION_CODE"/>
<xsl:template match="/root">
<xsl:for-each select="records/record[generate-id() = generate-id(key('opcode', OPERATION_CODE)[1])]">
<LaborOperationsDetail>
<LaborOperationID>
<xsl:value-of select="OPERATION_CODE"/>
</LaborOperationID>
<Combinations>
<xsl:for-each select="key('opcode' ,OPERATION_CODE)/Combinations/allowance">
<Allowance>
<GroupID>
<xsl:value-of select="WMI_CODE"/>
</GroupID>
<VID>
<xsl:value-of select="VDS_CODE"/>
</VID>
</Allowance>
</xsl:for-each>
</Combinations>
</LaborOperationsDetail>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
What you have now:
<xsl:for-each select="key('opcode' ,OPERATION_CODE)">
selects the two record nodes in the current group, and creates one Allowance node for each. Within these nodes, the values are retrieved from the first allowance in each record.