XSLT 1.0: key not working in selecting nodes - xslt

I have an XML and an XSLT that gives a current output. It uses a "key" but I am not getting the expected output
Source XML:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Receivers>
<ReceiverRule>
<Condition>
<Value>Condition 1</Value>
</Condition>
<Receiver>
<party>party1</party>
<system>SYS1</system>
</Receiver>
</ReceiverRule>
<ReceiverRule>
<Condition>
<Value>Condition 2</Value>
</Condition>
<Receiver>
<party>party2</party>
<system>SYS2</system>
</Receiver>
</ReceiverRule>
</Receivers>
<ReceiverInterfaces>
<Receiver>
<party>party1</party>
<system>SYS1</system>
</Receiver>
<ReceiverInterfaceRule>
<Rule>Rule 1 sytem 1</Rule>
</ReceiverInterfaceRule>
<ReceiverInterfaceRule>
<Rule>Rule 2 system 1</Rule>
</ReceiverInterfaceRule>
</ReceiverInterfaces>
<ReceiverInterfaces>
<Receiver>
<party>party2</party>
<system>SYS2</system>
</Receiver>
<ReceiverInterfaceRule>
<Rule>Rule 1 system 2</Rule>
</ReceiverInterfaceRule>
<ReceiverInterfaceRule>
<Rule>Rule 2 system 2</Rule>
</ReceiverInterfaceRule>
</ReceiverInterfaces>
</Root>
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="Receiver" match="ReceiverRule/Receiver" use="concat(party,system)"/>
<xsl:template match="Root">
<ReceiverList>
<xsl:apply-templates select="Receivers/ReceiverRule"/>
</ReceiverList>
</xsl:template>
<xsl:template match="ReceiverRule">
<Receiver>
<Name>
<xsl:value-of select="concat(Receiver/party, ' ' ,Receiver/system)"/>
</Name>
<Condition>
<xsl:value-of select="Condition/Value"/>
</Condition>
<xsl:apply-templates select="ancestor::Root/ReceiverInterfaces
[Receiver/child::* = key('Receiver',Root/Receivers/ReceiverRule/Receiver)]"/>
</Receiver>
</xsl:template>
<xsl:template match="ReceiverInterfaces">
<xsl:apply-templates select="ReceiverInterfaceRule"/>
</xsl:template>
<xsl:template match="ReceiverInterfaceRule">
<Rule>
<xsl:value-of select="Rule"/>
</Rule>
</xsl:template>
</xsl:stylesheet>
produces this XML output:
<?xml version="1.0" encoding="UTF-8"?>
<ReceiverList>
<Receiver>
<Name>party1 SYS1</Name>
<Condition>Condition 1</Condition>
</Receiver>
<Receiver>
<Name>party2 SYS2</Name>
<Condition>Condition 2</Condition>
</Receiver>
</ReceiverList>
But I am expecting this output:
<?xml version="1.0" encoding="UTF-8"?>
<ReceiverList>
<Receiver>
<Name>party1 SYS1</Name>
<Condition>Condition 1</Condition>
<Rule>Rule 1 sytem 1</Rule>
<Rule>Rule 2 system 1</Rule>
</Receiver>
<Receiver>
<Name>party2 SYS2</Name>
<Condition>Condition 2</Condition>
<Rule>Rule 1 system 2</Rule>
<Rule>Rule 2 system 2</Rule>
</Receiver>
</ReceiverList>
somehow my key is not recognized.

I think instead of
<xsl:apply-templates select="ancestor::Root/ReceiverInterfaces
[Receiver/child::* = key('Receiver',Root/Receivers/ReceiverRule/Receiver)]"/>
all you want is
<xsl:apply-templates select="key('Receiver', concat(Receiver/party, Receiver/system))/ReceiverInterfaceRule"/>
with the key as
<xsl:key name="Receiver" match="ReceiverInterfaces" use="concat(Receiver/party, Receiver/system)"/>

Related

I tried to remove specific element if its output is empty in XSLT

I am trying to remove Error Description element if it contains empty value using xslt. i tried lot of options but it does not work.
For example if inside Acknowledgement all the element get null then output get empty acknowledgement so I want remove acknowledgement element empty tag.
below is xml and xslt
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
XSLT :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl"/>
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001"/>
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE-->
<xsl:template match="/">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result"/>
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode"/>
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:template>
</xsl:stylesheet>
how can i achieve this?
I think this can be done if you're not thinking something big:
<xsl:if test="normalize-space(/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription) != ''">
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</xsl:if>
Edit:
One way to achieve this using extension function like exsl:node-set or msxsl:node-set to be able to further process a result tree fragment created in another template:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl" />
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001" />
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE -->
<xsl:template match="/">
<xsl:variable name="result">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result" />
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode" />
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription" />
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($result)/*" mode="step2" />
</xsl:template>
<xsl:template match="*[not(normalize-space())]" mode="step2" />
<xsl:template match="#* | node()" mode="step2">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="step2" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
http://xsltransform.net/93wkLHW
If you take a top-down aproach with literal result elements you are always going to get that element in the output. Your only choice then is to chain two transformations or use a two pass transformation.
The XPath expression to know whether the current node is empty (true) or not (false) is:
"not(node())"
For example, this input document
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
With this transformation
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements ="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]"/>
</xsl:stylesheet>
Output
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
</Acknowledgement>
</updateDocumentStatusResponse>
Edit
The previus stylesheet is general. If you want to target specific elements, you need to match those elements with the pattern in the template. Example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements ="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ErrorDescription[not(node())]"/>
</xsl:stylesheet>

Attempting to remove element and reorder elements in resulting document

I have the following XML and XSLT.
I am attempting to exclude the NotUsed2 element from the resulting document.
I need to reorder the resulting so that AutoTypesetInfo follows NotUsed3.
XML:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<Plan xmlns="http://www.ccieurope.com/xmlns/CCIPlanner">
<Header>
<Update>0</Update>
<NewsPaper>Pub1</NewsPaper>
<Date>080818</Date>
<Zone>MAIN</Zone>
<Edition>1st</Edition>
<Pages>26</Pages>
<Section>A B C </Section>
<Number>08082018</Number>
<Format>
<Height>21.70i</Height>
<Width>9.87i</Width>
</Format>
<PrintingInfo/>
<Version/>
<Config/>
<Default/>
<FileFormat>2.0</FileFormat>
<IssueName/>
</Header>
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>1</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#F</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>EditorialOnly</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed2/>
<NotUsed3/>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Desc1</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>710.9</AdWidth>
<AdHeight>144.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1404.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo></Page>
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>2</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#1</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>Mixed</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed2/>
<NotUsed3/>
<Ad>
<BookingNumber>152345</BookingNumber>
<Description>Description</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>000K</AdColor>
<AdWidth>351.9</AdWidth>
<AdHeight>360.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1188.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Description</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>351.9</AdWidth>
<AdHeight>360.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>358.99</XPos>
<YPos>1188.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo>
</Page>
</Plan>
XSL:
<?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"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci"
>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="NotUsed2" />
</xsl:stylesheet>
Expected in the resulting Page node:
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>1</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#F</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>EditorialOnly</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed3/>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Desc1</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>710.9</AdWidth>
<AdHeight>144.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1404.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
</Page>
I can't get the code to exclude the NotUsed2 element.
I'm not sure where to begin to tackle reordering the elements within nodes.
Any help would be appreciated.
Your NotUsed2 is not being removed because you have not accounted for the fact the element is in a default namespace in the XML. Your XSLT is looking for an element with no namespace.
You have declared the relevant namespace in your XSLT, so you just need to use the relevant prefix in the template match
<xsl:template match="cci:NotUsed2" />
For moving AutoTypesetInfo after NotUsed3 you should have a template that matches NotUsed3 where you can copy both the matched node, and the AutoTypesetInfo
<xsl:template match="cci:NotUsed3">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
<xsl:copy-of select="../cci:AutoTypesetInfo" />
</xsl:template>
You would also need a template to ensure the AutoTypesetInfo still doesn't get copied in its current position too
<xsl:template match="cci:AutoTypesetInfo" />
Try this XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci">
<xsl:output indent="yes"/>
<xsl:template match="#* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="cci:NotUsed2" />
<xsl:template match="cci:NotUsed3">
<xsl:call-template name="identity" />
<xsl:copy-of select="../cci:AutoTypesetInfo" />
</xsl:template>
<xsl:template match="cci:AutoTypesetInfo" />
</xsl:stylesheet>
This does assume NotUsed3 is always present. If not, change the last template to this to ensure the original AutoTypesetInfo is not removed in this case.
<xsl:template match="cci:AutoTypesetInfo[../cci:NotUsed3]" />
Try below XSLT.
<?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"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci"
>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="*[local-name()='NotUsed2']" />
</xsl:stylesheet>

How to create 1 group to sum 4 elements with xslt

I am trying to use muenchian to do a group/sum, but I can't make it work.
Any help available?! :)
XML I have:
<RLA760910>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-20</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>-15</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>100</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>105</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>411100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-30</SumBegBalance>
<SumDebitPeriod>5</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>-35</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>451100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>80</SumBegBalance>
<SumDebitPeriod>20</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>90</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
</RLA760910>
I've so far:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
<xsl:key name="AcctSub"
match="/RLA760910/G_L_By_Object_Account___Localization_S10"
use="#Zsz_ObjectAcctSub_OSBOW_ID3" />
<xsl:template match="Zsz_ObjectAcctSub_OSBOW_ID3">
<result>
<!-- Match the first acct element for a specific group -->
<xsl:apply-templates select="/RLA760910/G_L_By_Object_Account___Localization_S10/[generate-id() = generate-id(key('AcctSub', #Zsz_ObjectAcctSub_OSBOW_ID3)[1])]" />
</result>
</xsl:template>
<xsl:template match="/RLA760910/G_L_By_Object_Account___Localization_S10">
<total type="{#Zsz_ObjectAcctSub_OSBOW_ID3}">
<!-- Sum all the elements from the #type group -->
<xsl:value-of select="sum(key('AcctSub', #Zsz_ObjectAcctSub_OSBOW_ID3)/#Zsz_ObjectAcctSub_OSBOW_ID3)" />
</total>
</xsl:template>
</xsl:stylesheet>
Expected result will sum
SumBegBalance, SumDebitPeriod, SumCreditPeriod, SumEndBalance Group BY Zsz_ObjectAcctSub_OSBOW_ID3
Use the following script:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:key name="AcctSub"
match="G_L_By_Object_Account___Localization_S10"
use="Zsz_ObjectAcctSub_OSBOW_ID3"/>
<xsl:template match="RLA760910">
<xsl:copy>
<xsl:for-each select="*[generate-id()=generate-id(
key('AcctSub', Zsz_ObjectAcctSub_OSBOW_ID3)[1])]">
<result>
<xsl:variable name="Objects" select="key('AcctSub',
Zsz_ObjectAcctSub_OSBOW_ID3)"/>
<Zsz_ObjectAcctSub_OSBOW_ID3>
<xsl:value-of select="Zsz_ObjectAcctSub_OSBOW_ID3"/>
</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>
<xsl:value-of select="sum($Objects/SumBegBalance)"/>
</SumBegBalance>
<SumDebitPeriod>
<xsl:value-of select="sum($Objects/SumDebitPeriod)"/>
</SumDebitPeriod>
<SumCreditPeriod>
<xsl:value-of select="sum($Objects/SumCreditPeriod)"/>
</SumCreditPeriod>
<SumEndBalance>
<xsl:value-of select="sum($Objects/SumEndBalance)"/>
</SumEndBalance>
</result>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
A few notes:
Zsz_ObjectAcctSub_OSBOW_ID3 is not an atribute but an element, so #
is not needed.
As the name of the root tag I used the same name as in your input.
Each result output tag contains Zsz_ObjectAcctSub_OSBOW_ID3 tag
(the grouping key) and sums of your 4 tags (within the group).
Try this as your 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:key name="grp" match="G_L_By_Object_Account___Localization_S10" use="Zsz_ObjectAcctSub_OSBOW_ID3" />
<xsl:template match="/RLA760910">
<result>
<xsl:for-each select="G_L_By_Object_Account___Localization_S10[generate-id() = generate-id(key('grp', Zsz_ObjectAcctSub_OSBOW_ID3)[1])]" >
<group type="{Zsz_ObjectAcctSub_OSBOW_ID3}">
<total-of-begbalance>
<xsl:value-of select="sum(key('grp', Zsz_ObjectAcctSub_OSBOW_ID3)/SumBegBalance)"/>
</total-of-begbalance>
<!-- add more totals here-->
</group>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
When this is applied to the following well-formed example input:
XML
<RLA760910>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-20</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>-15</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>100</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>105</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>411100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-30</SumBegBalance>
<SumDebitPeriod>5</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>-35</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>451100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>80</SumBegBalance>
<SumDebitPeriod>20</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>90</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
</RLA760910>
the result will be:
<?xml version="1.0" encoding="utf-8"?>
<result>
<group type="401100.900">
<total-of-begbalance>80</total-of-begbalance>
</group>
<group type="411100.900">
<total-of-begbalance>-30</total-of-begbalance>
</group>
<group type="451100.900">
<total-of-begbalance>80</total-of-begbalance>
</group>
</result>
Note that your expressions using #Zsz_ObjectAcctSub_OSBOW_ID3 fail because Zsz_ObjectAcctSub_OSBOW_ID3 is an element, not an attribute.

Include tags in XSLT for every copy

Below is the input xml:-
<request version="1" type="PrintFPDPackInput">
<keys>
<key name="Date" value="02/01/2010 01:00:25" />
<key name="AmtGross" value="22.33" />
<key name="AmtNet" value="17.86" />
<key name="ContribType" value="Individual" />
<key name="Date" value="01/01/2010 01:00:26" />
<key name="AmtGross" value="22.25" />
<key name="AmtNet" value="17.80" />
<key name="ContribType" value="Individual" />
<key name="Date" value="12/01/2009 01:00:27" />
<key name="AmtGross" value="22.25" />
<key name="AmtNet" value="17.80" />
<key name="ContribType" value="Individual" />
</keys>
</request>
The XSLT processed :-
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<!-- <xsl:param name="User"/>
<xsl:param name="Password"/> -->
<xsl:template match="/">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:fpd="http://zip.uk.zurich.com/fpdservice">
<soapenv:Header/>
<soapenv:Body>
<fpd:CheckFPD>
<xsl:copy>
<policy>
<xsl:apply-templates select="request/keys/key[#name = 'Date' or #name = 'AmtGross' or #name = 'AmtNet' or #name = 'ContribType']" />
</policy>
</xsl:copy>
</fpd:CheckFPD>
</soapenv:Body>
</soapenv:Envelope>
</xsl:template>
<xsl:template match="key[#name = 'Date' or #name = 'AmtGross' or #name = 'AmtNet' or #name = 'ContribType' ]">
<xsl:element name="{#name}">
<xsl:value-of select="#value" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This is the error output I am getting as below: http://xslttest.appspot.com/
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:fpd="http://zip.uk.zurich.com/fpdservice">
<soapenv:Header/>
<soapenv:Body>
<fpd:CheckFPD>
<policy>
<Date>02/01/2010 01:00:25</Date>
<AmtGross>22.33</AmtGross>
<AmtNet>17.86</AmtNet>
<ContribType>Individual</ContribType>
<Date>01/01/2010 01:00:26</Date>
<AmtGross>22.25</AmtGross>
<AmtNet>17.80</AmtNet>
<ContribType>Individual</ContribType>
<Date>12/01/2009 01:00:27</Date>
<AmtGross>22.25</AmtGross>
<AmtNet>17.80</AmtNet>
<ContribType>Individual</ContribType>
</policy>
</fpd:CheckFPD>
</soapenv:Body>
</soapenv:Envelope>
Expected output as below format:-
<ListOfPolicyReceipts>
<PolicyReceipts>
<Date>02/01/2010 01:00:25</Date>
<AmtGross>22.33</AmtGross>
<AmtNet>17.86</AmtNet>
<ContribType>Individual</ContribType>
</PolicyReceipts>
<PolicyReceipts>
<Date>01/01/2010 01:00:26</Date>
<AmtGross>22.25</AmtGross>
<AmtNet>17.80</AmtNet>
<ContribType>Individual</ContribType>
</PolicyReceipts>
<PolicyReceipts>
<Date>12/01/2009 01:00:27</Date>
<AmtGross>22.25</AmtGross>
<AmtNet>17.80</AmtNet>
<ContribType>Individual</ContribType>
</PolicyReceipts>
Kindly suggest process the tags PolicyReceipts is applied for every copy of data
I can not see the xsd, so I assume, the tag ListOfPolicyReceipts will replace the tag policy. But i am pretty sure, you can implement the following code on the correct place in your stylesheet.
Probably you can use this one:
<ListOfPolicyReceipts>
<xsl:for-each select="request/keys/key[#name = 'Date']">
<PolicyReceipts>
<xsl:apply-templates select=". | following-sibling::key[#name = 'AmtGross'][1] | following-sibling::key[#name = 'AmtNet'][1] | following-sibling::key[#name = 'ContribType'][1]"/>
</PolicyReceipts>
</xsl:for-each>
</ListOfPolicyReceipts>
Important:
all 4 elements with name date, AmtGross, AmtNet and ContribType have to be in that specific order!
all 4 elements have to be present; if one is missing, the xslt will fail and output wrong data [probably the output is valid, but the content is wrong]
The posted expected output can be achieved quite simply 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:template match="/request">
<ListOfPolicyReceipts>
<xsl:apply-templates select="keys/key[#name = 'Date']"/>
</ListOfPolicyReceipts>
</xsl:template>
<xsl:template match="key">
<PolicyReceipts>
<xsl:for-each select=". | following-sibling::key[position() < 4]">
<xsl:element name="{#name}">
<xsl:value-of select="#value" />
</xsl:element>
</xsl:for-each>
</PolicyReceipts>
</xsl:template>
</xsl:stylesheet>
This is assuming the input will always list the key elements in groups of 4, with <key name="Date"> being the first in its group.

A sequence of more than one item is not allowed as the second argument of concat()

The below xsl works fine if I do not bring in the "other_location_postal_code" field, which is commented here.
This is because there are multiple records if I bring in that field.
How can I have this xsl evaluate each record so it would write this record twice, once for the one "other location postal code" and the other?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:e="http://www.taleo.com/ws/tee800/2009/01" xmlns:fct="http://www.taleo.com/xsl_functions" exclude-result-prefixes="e fct">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="no"/>
<xsl:param name="OUTBOUND_FOLDER"/>
<xsl:template match="/">
<source>
<xsl:apply-templates select="//e:Requisition"/>
</source>
</xsl:template>
<xsl:template match="e:Requisition">
<xsl:variable name="job_id" select="e:ContestNumber"/>
<xsl:variable name="other_location_postal_code" select="e:JobInformation/e:JobInformation/e:OtherLocations/e:Location/e:NetworkLocation/e:NetworkLocation/e:ZipCode"/>
<job>
<job_id>
<xsl:value-of select="concat('<','![CDATA[',$job_id,']]','>')"/>
</job_id>
<other_location_postal_code>
<xsl:value-of select="concat('![CDATA[',$other_location_postal_code,']]')"/>
</other_location_postal_code>
</job>
</xsl:template>
</xsl:stylesheet>
I want it to come out like so:
<?xml version="1.0" encoding="UTF-8"?>
<source>
<job>
<job_id><![CDATA[15000005]]></job_id>
<other_location_postal_code><![CDATA[77382]]></other_location_postal_code>
</job>
<job>
<job_id><![CDATA[15000005]]></job_id>
<other_location_postal_code><![CDATA[37567]]></other_location_postal_code>
</job>
</source>
The initial XML looks like so:
<?xml version="1.0" encoding="UTF-8"?>
-<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
-<soapenv:Body>
-<ns1:getDocumentByKeyResponse xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
-<Document xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
-<Attributes>
<Attribute name="count">1</Attribute>
<Attribute name="duration">0:00:00.088</Attribute>
<Attribute name="entity">Requisition</Attribute>
<Attribute name="mode">T-XML</Attribute>
<Attribute name="version">http://www.taleo.com/ws/tee800/2009/01</Attribute>
</Attributes>
-<Content>
-<ExportTXML xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:e="http://www.taleo.com/ws/tee800/2009/01">
-<e:Requisition>
<e:ContestNumber>15000005</e:ContestNumber>
-<e:JobInformation>
-<e:JobInformation>
-<e:OtherLocations>
-<e:Location>
<e:ZipCode>77002</e:ZipCode>
</e:Location>
-<e:Location>
<e:ZipCode>77050</e:ZipCode>
</e:Location>
</e:OtherLocations>
</e:JobInformation>
</e:JobInformation>
</e:Requisition>
</ExportTXML>
</Content>
</Document>
</ns1:getDocumentByKeyResponse>
</soapenv:Body>
</soapenv:Envelope>
The error message simply says that an argument to the concat function is a sequence of more than one node. So some of your variable selects two or more nodes and concat expects as single node for each of its arguments. You will need to decide what you want to output, either only the first node with $var[1] or the concatenation with string-join($var, ' ').
Note that you don't need all those attempts to output CDATA section, you can tell the XSLT processor the cdata-section-elements on the xsl:output direction.
As you have now posted more details here is one suggestion to map each ZipCode element to job element:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:e="http://www.taleo.com/ws/tee800/2009/01"
exclude-result-prefixes="e">
<xsl:output indent="yes" cdata-section-elements="job_id other_location_postal_code"/>
<xsl:template match="/">
<source>
<xsl:apply-templates select="//e:OtherLocations/e:Location/e:ZipCode"/>
</source>
</xsl:template>
<xsl:template match="e:ZipCode">
<xsl:apply-templates select="ancestor::e:Requisition">
<xsl:with-param name="zc" select="current()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="e:Requisition">
<xsl:param name="zc"/>
<job>
<job_id><xsl:value-of select="e:ContestNumber"/></job_id>
<other_location_postal_code><xsl:value-of select="$zc"/></other_location_postal_code>
</job>
</xsl:template>
</xsl:stylesheet>