I am fighting a pretty extreme case of transforming a flat XML into a hierarchical one. I'm also stuck with using XSLT 1.0. My actual case is pretty convoluted, but I think I can reduce it down to something like this:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<tns:getDataRS xmlns:tns="http://www.myco.com/DataService">
<tns:Acknowledgement>Process completed successfully.</tns:Acknowledgement>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:storeOrder>28</tns:storeOrder>
<tns:itemID>1</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:storeOrder>28</tns:storeOrder>
<tns:itemID>3</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:storeOrder>48</tns:storeOrder>
<tns:itemID>2</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:storeOrder>48</tns:storeOrder>
<tns:itemID>4</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:item>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:itemID>1</tns:itemID>
<tns:unitPrice>2.95</tns:unitPrice>
<tns:quantity>4</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:itemID>2</tns:itemID>
<tns:unitPrice>3.29</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:itemID>3</tns:itemID>
<tns:unitPrice>4.99</tns:unitPrice>
<tns:quantity>1</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:itemID>4</tns:itemID>
<tns:unitPrice>6.95</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
</tns:getDataRS>
</env:Body>
</env:Envelope>
And it needs to become:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<tns:getDataRS xmlns:tns="http://www.myco.com/DataService">
<tns:Acknowledgement>Process completed successfully.</tns:Acknowledgement>
<tns:stores>
<tns:store>
<tns:storeID>1</tns:storeID>
<tns:orders>
<tns:order>28</tns:order>
<tns:salesDate>2014-09-26</tns:salesDate>
<tns:customers>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:items>
<tns:item>
<tns:itemID>1</tns:itemID>
<tns:unitPrice>2.95</tns:unitPrice>
<tns:quantity>4</tns:quantity>
</tns:item>
<tns:item>
<tns:itemID>3</tns:itemID>
<tns:unitPrice>4.99</tns:unitPrice>
<tns:quantity>1</tns:quantity>
</tns:item>
</tns:items>
</tns:customer>
</tns:customers>
</tns:orders>
</tns:store>
<tns:store>
<tns:storeID>2</tns:storeID>
<tns:orders>
<tns:order>48</tns:order>
<tns:salesDate>2014-09-26</tns:salesDate>
<tns:customers>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:items>
<tns:item>
<tns:itemID>2</tns:itemID>
<tns:unitPrice>3.29</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
<tns:item>
<tns:itemID>4</tns:itemID>
<tns:unitPrice>6.95</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
</tns:items>
</tns:customer>
</tns:customers>
</tns:orders>
</tns:store>
</tns:stores>
</tns:getDataRS>
</env:Body>
</env:Envelope>
And though I know I need to create a number of keys, I can't quite figure out the proper matching to extract and map the data.
I'd really like some help getting started.
I'd really like some help getting started.
Try this as your starting point:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tns="http://www.myco.com/DataService">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="store" match="tns:storeID" use="." />
<xsl:key name="order-by-store" match="tns:storeOrder" use="../tns:storeID" />
<xsl:key name="order-by-id" match="tns:storeOrder" use="." />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tns:getDataRS">
<xsl:copy>
<xsl:copy-of select="tns:Acknowledgement"/>
<tns:stores>
<xsl:apply-templates select="tns:customer/tns:storeID[count(. | key('store', .)[1]) = 1]"/>
</tns:stores>
</xsl:copy>
</xsl:template>
<xsl:template match="tns:storeID">
<tns:store>
<xsl:copy-of select="."/>
<tns:orders>
<xsl:apply-templates select="key('order-by-store', .)[count(. | key('order-by-id', .)[1]) = 1]"/>
</tns:orders>
</tns:store>
</xsl:template>
<xsl:template match="tns:storeOrder">
<tns:Order><xsl:value-of select="."/></tns:Order>
<tns:customers>
<!-- continue from here... -->
</tns:customers>
</xsl:template>
</xsl:stylesheet>
I am not sure how to continue from this point on, even if I wanted to: I don't see that you have multiple customers per order, and as I said in the comments, the relationship between orders and visits is not quite clear either.
Related
My XML is below. Is it possible to do this in same XSLT?
<response context="XXXX" type="abcd" errorCode="0" >
<output>
<Applicants>
<Applicant>
<IndividualEmployments/>
<Addresses/>
</Applicant>
</Applicants>
<Assets>
<Asset id="12345"></Asset>
</Assets>
<Liabilities>
<Liability id="8765"></Liability>
</Liabilities>
</output>
Desired output should be like below. I want two response nodes, one with Assets and the other with Liabilities.
<response context="XXXX" type="abcd" errorCode="0">
<output>
<Applicants>
<Applicant>
<IndividualEmployments/>
<Addresses/>
</Applicant>
</Applicants>
<Assets>
<Asset id="12345"></Asset>
</Assets>
</output>
<response context="XXXX" type="abcd" errorCode="0">
<output>
<Applicants>
<Applicant>
<IndividualEmployments/>
<Addresses/>
</Applicant>
</Applicants>
<Liabilities>
<Liability id="8765"></Liability>
</Liabilities>
</output>
You need to process the response element and output it twice, making sure the content is different, for instance by passing a parameter:
<?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"
expand-text="yes">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="response">
<xsl:next-match>
<xsl:with-param name="exclude" tunnel="yes" select="descendant::Liabilities"/>
</xsl:next-match>
<xsl:next-match>
<xsl:with-param name="exclude" tunnel="yes" select="descendant::Assets"/>
</xsl:next-match>
</xsl:template>
<xsl:template match="output">
<xsl:param name="exclude" tunnel="yes"/>
<xsl:copy>
<xsl:apply-templates select="#*, node() except $exclude"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If needed or wanted you can of course wrap each xsl:next-match I have in an xsl:result-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>
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.
I want to split an XmlDocument into an array of XmlDocuments, where each splitted XmlDocument contains records of a certain period (Year/Month combination). The complicating factor, imo, is that the grouping should occur on nested elements.
Example input:
<?xml version="1.0" encoding="utf-8"?>
<Example>
<RecordA>
<RecordA1>
<RecordA11>
<ElementA11></ElementA11>
</RecordA11>
</RecordA1>
<RecordA2>
<ElementA2></ElementA2>
</RecordA2>
</RecordA>
<RecordB>
<RecordB1>
<ElementB1></ElementB1>
<RecordB11>
<ElementB11></ElementB11>
<RecordB111>
<RecordB1111>
<RecordB11111>
<ElementB11111></ElementB11111>
</RecordB11111>
<ElementB1111></ElementB1111>
<RecordB11112>
<Dates>
<StartDate>2014-05-29</StartDate>
<EndDate>2014-05-29</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-06-02</StartDate>
<EndDate>2014-06-02</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-05-21</StartDate>
<EndDate>2014-05-21</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-04-09</StartDate>
<EndDate>2014-04-09</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-06-05</StartDate>
<EndDate>2014-06-05</EndDate>
</Dates>
</RecordB11112>
</RecordB1111>
</RecordB111>
</RecordB11>
</RecordB1>
</RecordB>
</Example>
Wanted output:
<?xml version="1.0" encoding="utf-8"?>
<Examples>
<Example>
<RecordA>
<RecordA1>
<RecordA11>
<ElementA11></ElementA11>
</RecordA11>
</RecordA1>
<RecordA2>
<ElementA2></ElementA2>
</RecordA2>
</RecordA>
<RecordB>
<RecordB1>
<ElementB1></ElementB1>
<RecordB11>
<ElementB11></ElementB11>
<RecordB111>
<RecordB1111>
<RecordB11111>
<ElementB11111></ElementB11111>
</RecordB11111>
<ElementB1111></ElementB1111>
<RecordB11112>
<Dates>
<StartDate>2014-05-29</StartDate>
<EndDate>2014-05-29</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-05-21</StartDate>
<EndDate>2014-05-21</EndDate>
</Dates>
</RecordB11112>
</RecordB1111>
</RecordB111>
</RecordB11>
</RecordB1>
</RecordB>
</Example>
<Example>
<RecordA>
<RecordA1>
<RecordA11>
<ElementA11></ElementA11>
</RecordA11>
</RecordA1>
<RecordA2>
<ElementA2></ElementA2>
</RecordA2>
</RecordA>
<RecordB>
<RecordB1>
<ElementB1></ElementB1>
<RecordB11>
<ElementB11></ElementB11>
<RecordB111>
<RecordB1111>
<RecordB11111>
<ElementB11111></ElementB11111>
</RecordB11111>
<ElementB1111></ElementB1111>
<RecordB11112>
<Dates>
<StartDate>2014-04-09</StartDate>
<EndDate>2014-04-09</EndDate>
</Dates>
</RecordB11112>
</RecordB1111>
</RecordB111>
</RecordB11>
</RecordB1>
</RecordB>
</Example>
<Example>
<RecordA>
<RecordA1>
<RecordA11>
<ElementA11></ElementA11>
</RecordA11>
</RecordA1>
<RecordA2>
<ElementA2></ElementA2>
</RecordA2>
</RecordA>
<RecordB>
<RecordB1>
<ElementB1></ElementB1>
<RecordB11>
<ElementB11></ElementB11>
<RecordB111>
<RecordB1111>
<RecordB11111>
<ElementB11111></ElementB11111>
</RecordB11111>
<ElementB1111></ElementB1111>
<RecordB11112>
<Dates>
<StartDate>2014-06-02</StartDate>
<EndDate>2014-06-02</EndDate>
</Dates>
</RecordB11112>
<RecordB11112>
<Dates>
<StartDate>2014-06-05</StartDate>
<EndDate>2014-06-05</EndDate>
</Dates>
</RecordB11112>
</RecordB1111>
</RecordB111>
</RecordB11>
</RecordB1>
</RecordB>
</Example>
</Examples>
I think you can use Muenchian grouping to identify the first item in each group, then you need to recreate the tree for each group:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="RecordB11112" use="substring(Dates/StartDate, 1, 7)"/>
<xsl:template match="/">
<Examples>
<xsl:apply-templates select="//RecordB11112[generate-id() = generate-id(key('group', substring(Dates/StartDate, 1, 7))[1])]"/>
</Examples>
</xsl:template>
<xsl:template match="RecordB11112">
<xsl:variable name="to-be-copied" select="key('group', substring(Dates/StartDate, 1, 7))"/>
<xsl:apply-templates select="/*" mode="recreate">
<xsl:with-param name="to-be-copied" select="$to-be-copied"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="#* | node()" mode="recreate">
<xsl:param name="to-be-copied"/>
<xsl:copy>
<xsl:apply-templates select="#*" mode="recreate"/>
<xsl:apply-templates mode="recreate">
<xsl:with-param name="to-be-copied" select="$to-be-copied"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="RecordB11112" mode="recreate">
<xsl:param name="to-be-copied"/>
<xsl:if test="$to-be-copied[generate-id() = generate-id(current())]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I am trying to transform XML into another XML file but unsuccessfully changing a flat element into an expanded element.
The output should be identical except DateOfBirth should be changed to:
<DateOfBirth>
<FullDate xmlns="cds_dt">1966-02-11</FullDate>
</DateOfBirth>
Here are the input files I am using:
Input
*****
<?xml version="1.0" encoding="utf-8"?>
<RootRec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="cds">
<MyRecord>
<Demographics>
<Names>
<LegalName namePurpose="L" xmlns="cds_dt">
<FirstName>
<Part>Jason</Part>
<PartType>GIV</PartType>
</FirstName>
<LastName>
<Part>Smith</Part>
<PartType>FAMC</PartType>
</LastName>
<OtherName>
<Part>Lauren</Part>
<PartType>GIV</PartType>
</OtherName>
</LegalName>
</Names>
<DateOfBirth>1966-02-11</DateOfBirth>
<Demographics>
<MyRecord>
</RootRec>
XSL file
********
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!--Identity Template. This will copy everything as-is.-->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!--expand "DateOfBirth" element to /DateOfBirth/FullDate element.-->
<xsl:template match="RootRec/MyRecord/Demographics/DateOfBirth">
<DateOfBirth>
<FullDate><xsl:value-of select="DateOfBirth"/></FullDate>
</DateOfBirth>
</xsl:template>
</xsl:stylesheet>
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="cds">
<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="x:DateOfBirth/text()">
<xsl:element name="FullDate" xmlns="cds_dt"><xsl:value-of select="."/></xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the provided (corrected to be made wellformed) XML document:
<RootRec
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="cds">
<MyRecord>
<Demographics>
<Names>
<LegalName namePurpose="L" xmlns="cds_dt">
<FirstName>
<Part>Jason</Part>
<PartType>GIV</PartType>
</FirstName>
<LastName>
<Part>Smith</Part>
<PartType>FAMC</PartType>
</LastName>
<OtherName>
<Part>Lauren</Part>
<PartType>GIV</PartType>
</OtherName>
</LegalName>
</Names>
<DateOfBirth>1966-02-11</DateOfBirth>
</Demographics>
</MyRecord>
</RootRec>
produces the wanted, correct result:
<RootRec xmlns="cds" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyRecord>
<Demographics>
<Names>
<LegalName xmlns="cds_dt" namePurpose="L">
<FirstName>
<Part>Jason</Part>
<PartType>GIV</PartType>
</FirstName>
<LastName>
<Part>Smith</Part>
<PartType>FAMC</PartType>
</LastName>
<OtherName>
<Part>Lauren</Part>
<PartType>GIV</PartType>
</OtherName>
</LegalName>
</Names>
<DateOfBirth>
<FullDate xmlns="cds_dt">1966-02-11</FullDate>
</DateOfBirth>
</Demographics>
</MyRecord>
</RootRec>
Explanation: Overriding the identity rule.
It should be
<FullDate><xsl:value-of select="."/></FullDate>
since you're already selecting the DateOfBirth in the match=""
You also have missing / in the three closing tags before the document end, and your namespace names are invalid because they must be absolute URIs.
Good luck.