XSLT - Delete XML nodes comparing dates - xslt

For below XML i need to delete all XML nodes of only Unit 6000 when field StartDate is not equal to any of the StartDate items of unit 5000
I tried to match a template but does to seems to be a good match
<?xml version="1.0" encoding="UTF-8"?>
<AllRecords>
<Records>
<Record>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST1</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2020-12-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST2</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2020-05-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-02-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST3</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-02-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2020-12-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2000</company>
<Newplant>TEST4</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2020-01-01T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2010</company>
<Newplant>TEST5</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-06-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2020</company>
<Newplant>TEST5</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-093T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
</Record>
</Records>
</AllRecords>
xslt code
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
</xsl:stylesheet>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="date" select="xs:date(//Items[Status = 'A' and ( Unit=6000)) ]/StartDate
<xsl:template match="$date eq xs:date(//Items[Status = 'A' and Unit='5000']/StartDate)"/>
</xsl:stylesheet>
Expected Output XSLT code after deleting unit 6000 XML nodes as these 2 nodes dates does not match with any one the xml node of 5000
<?xml version="1.0" encoding="UTF-8"?>
<AllRecords>
<Records>
<Record>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST1</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2020-12-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST2</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2020-05-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-02-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST3</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2010</company>
<Newplant>TEST5</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
</Record>
</Records>
</AllRecords>

delete all XML nodes of only Unit 6000 when field StartDate is not equal to any of the StartDate items of unit 5000
That should be very easy to accomplish using a 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="Items[Unit=5000]" use="StartDate" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- remove items that do not have a matching item -->
<xsl:template match="Items[Unit=6000][not(key('k1', StartDate))]"/>
</xsl:stylesheet>

Besides #micheal.hor257k good answer, this kind of problem can be easyly done with simple XPath/XSLT patterns:
<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:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="Items[Unit=6000][not(StartDate = ../Items[Unit=5000]/StartDate)]"/>
</xsl:stylesheet>
Check it here

Related

Restructure xml with recursive nodes

I have an issue in SAP PI with an xml with recursive nodes. I have a Container which can have a SubContainer with (another) Container.
Input xml
<Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer">
<Container>
<Name>INTERIEUR1</Name>
<Number>1</Number>
<SSCC>111</SSCC>
<SubContainers>
<Container>
<Id>I1371851</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>ACCESSOIRE1</Name>
<Barcode>181001371851</Barcode>
<Items>
<Item>
<Id>I8709475</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
<Item>
<Id>I8709476</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
<Container>
<Id>I1371852</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>PANEEL1</Name>
<Barcode>181001371852</Barcode>
<Items>
<Item>
<Id>I8709492</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
</SubContainers>
</Container>
Challenge: I want to move the child Container nodes of the SubContainers to the root level and use the value of SSCC in these nodes. Thus getting rid of the SubContainers element.
Required result
<Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer">
<Container>
<Id>I1371851</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>ACCESSOIRE1</Name>
<SSCC>111</SSCC>
<Barcode>181001371851</Barcode>
<Items>
<Item>
<Id>I8709475</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
<Item>
<Id>I8709476</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
<Container>
<Id>I1371852</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>PANEEL1</Name>
<SSCC>111</SSCC>
<Barcode>181001371852</Barcode>
<Items>
<Item>
<Id>I8709492</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
</Container>
</Containers>
</Containers>
My current xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="https://www.uniconcreation.com/2021/IvenzaShippingContainer" exclude-result-prefixes="ext">
<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="ext:Name|ext:Number|ext:SSCC|#*" />
<xsl:template match="ext:Containers/ext:Container/ext:SubContainers[ext:Container]">
<xsl:variable name="sscc" select="/ext:Containers/ext:Container/ext:SSCC"/>
<xsl:for-each select="*">
<xsl:element name="SSCC" namespace="{namespace-uri()}">
<xsl:value-of select="$sscc" /></xsl:element>
<xsl:copy-of select="node()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I'm not doing a real great job if you look at my result on xsltfiddle :(
I'm stuck with the original parent and I don't manage to get the 2 elements around my child nodes.
Kind regards,
Mike D
If I am guessing correctly, all you need to do is simply:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="https://www.uniconcreation.com/2021/IvenzaShippingContainer">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Containers">
<xsl:variable name="sscc" select="Container/SSCC"/>
<xsl:copy>
<xsl:for-each select="//SubContainers/Container">
<xsl:copy>
<xsl:copy-of select="* except (Barcode, Items)"/>
<xsl:copy-of select="$sscc"/>
<xsl:copy-of select="Barcode, Items"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer">
<Container>
<Id>I1371851</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>ACCESSOIRE1</Name>
<SSCC>111</SSCC>
<Barcode>181001371851</Barcode>
<Items>
<Item>
<Id>I8709475</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
<Item>
<Id>I8709476</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
<Container>
<Id>I1371852</Id>
<SalesOrderNumber>2012231</SalesOrderNumber>
<ProductionOrderNumber>I2017658</ProductionOrderNumber>
<Name>PANEEL1</Name>
<SSCC>111</SSCC>
<Barcode>181001371852</Barcode>
<Items>
<Item>
<Id>I8709492</Id>
<SalesOrderRowId>I671068</SalesOrderRowId>
<SalesOrderRowExternalReference>1</SalesOrderRowExternalReference>
<Quantity>1</Quantity>
</Item>
</Items>
</Container>
</Containers>
If the exact order of the child elements of Container does not matter, then it could be even simpler. Instead of:
<xsl:copy-of select="* except (Barcode, Items)"/>
<xsl:copy-of select="$sscc"/>
<xsl:copy-of select="Barcode, Items"/>
you could do:
<xsl:copy-of select="$sscc | *"/>

XSLT - Filter XML nodes with dates and current date ()

For below XML i need to delete all XML nodes of only Unit 6000 when field StartDate is not equal to any of the StartDate items of unit 5000 and (also make sure startDate is less than equal to current date and EndDate is greater than or equal to current date)
I tried to match a template but does to seems to be a good match
<?xml version="1.0" encoding="UTF-8"?>
<AllRecords>
<Records>
<Record>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST1</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2020-12-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST2</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2020-05-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-02-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>1000</company>
<Newplant>TEST3</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-02-01T00:00:00.000</StartDate>
<Unit>5000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2020-12-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2000</company>
<Newplant>TEST4</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2020-01-01T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-03-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2010</company>
<Newplant>TEST5</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-01T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
<Items>
<EndDate>2021-06-31T00:00:00.000</EndDate>
<PlantDetails>
<PlantDetailsUS>
<company>2020</company>
<Newplant>TEST5</Newplant>
</PlantDetailsUS>
</PlantDetails>
<StartDate>2021-01-093T00:00:00.000</StartDate>
<Unit>6000</Unit>
<Status>A</Status>
</Items>
</Record>
</Records>
</AllRecords>
XSLT Code
<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:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="Items[Unit=6000][not(StartDate = ../Items[Unit=5000]/StartDate)] [(StartDate <= current-date())] [(EndDate >= current-date())]"/>
</xsl:stylesheet>
First thing: in order to compare dates to current date you need XSLT 2.0 (or an alternative way to get the current date in XSLT 1.0, e.g. an extension function or a parameter).
Next, your input contains dateTimes, not dates. To make a valid comparison, you need to either compare them to the current dateTime or convert them to dates before comparing them to the current date. Try:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="k1" match="Items[Unit=5000]" use="StartDate" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Items[Unit=6000][not(key('k1', StartDate)) or xs:date(substring(StartDate, 1, 10)) gt current-date() or xs:date(substring(EndDate, 1, 10)) lt current-date()]"/>
</xsl:stylesheet>

Multiply 2 filtered numbers and sum

I need to sum the multiplication of 2 numbers based on this example
<test>
<stop>
<id>1</id>
<unit_id>1</unit_id>
<unit_id>2</unit_id>
</stop>
<stop>
<id>2</id>
<unit_id>1</unit_id>
<unit_id>3</unit_id>
</stop>
<unit>
<id>1</id>
<count>2</count>
<value>1</value>
</unit>
<unit>
<id>2</id>
<count>4</count>
<value>1</value>
</unit>
<unit>
<id>3</id>
<count>2</count>
<value>3</value>
</unit>
The result i want to get is the one below
<test>
<stop>
<id>1</id>
<sum>6</sum>
</stop>
<stop>
<id>2</id>
<sum>10</sum>
</stop>
Any tips how to get it?
I tried with this example but the sum of the moltiplication doesn't work, it is ok for only the sum or the multiplication but not both
<xsl:template match="stop">
<xsl:variable name="ship_unit" select="id"/>
<xsl:value-of select="sum(following-sibling::unit[id=$ship_unit]/count*following-sibling::unit[id=$ship_unit]/value)"/>
If I am guessing correctly, you want to do something like:
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="unit" match="unit" use="id" />
<xsl:template match="/test">
<xsl:copy>
<xsl:for-each select="stop">
<xsl:variable name="unit1" select="key('unit', unit_id[1])" />
<xsl:variable name="unit2" select="key('unit', unit_id[2])" />
<xsl:copy>
<xsl:copy-of select="id"/>
<sum>
<xsl:value-of select="$unit1/count * $unit1/value + $unit2/count * $unit2/value" />
</sum>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However, the result of applying this to your input example will be:
<?xml version="1.0" encoding="utf-8"?>
<test>
<stop>
<id>1</id>
<sum>6</sum>
</stop>
<stop>
<id>2</id>
<sum>8</sum>
</stop>
</test>
and not what you posted.

Need to merge 2 xml in xslt based on a common key

I have 2 source variables which need to be merged based on a common key in XSLT
Variable 1:I have added few properties for each employee.
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Emp>
</EmpDetails>
Variable 2:
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
<EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
<EmpAge>
</EmpAgeDetails>
Expected output:
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Age>27</Age>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Age>26</Age>
<Emp>
</EmpDetails>
I am using a template to copy all elements from Variable 1 which is working fine.
But now I need to merge that extra element of Age.
Any help is appreciated
Using XSLT 3.0 and xsl:merge, as supported in the latest Altova XMLSpy/Raptor or Saxon 9.7 EE, you can use
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="array fn map math xs">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="xsl:initial-template">
<EmpDetails>
<xsl:merge>
<xsl:merge-source select="$doc1/EmpDetails/Emp">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-source select="$doc2/EmpAgeDetails/EmpAge">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:apply-templates select="current-merge-group()[1]/*, fn:current-merge-group()[2]/Age"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>
Using XSLT 2.0 you could group:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="main">
<EmpDetails>
<xsl:for-each-group select="$doc1/EmpDetails/Emp, $doc2/EmpAgeDetails/EmpAge" group-by="ID">
<xsl:copy>
<xsl:copy-of select="current-group()[1]/*, current-group()[2]/Age"/>
</xsl:copy>
</xsl:for-each-group>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>

How to sort min value using xslt?

below is my xml file called test.xml
<products>
<supplier>
<supplierid>1001</supplierid>
<totalprice>30</totalprice>
<items>
<item>Pen</item>
<price>10</price>
</items>
<items>
<item>Pencil</item>
<price>5</price>
</items>
<items>
<item>Bag</item>
<price>15</price>
</items>
</supplier>
<supplier>
<supplierid>1001</supplierid>
<totalprice>23</totalprice>
<items>
<item>Pencil</item>
<price>8</price>
</items>
<items>
<item>Pen</item>
<price>5</price>
</items>
<items>
<item>Bag</item>
<price>10</price>
</items>
</supplier>
<supplier>
<supplierid>1001</supplierid>
<totalprice>24</totalprice>
<items>
<item>Paper Box</item>
<price>7</price>
</items>
<items>
<item>Pen</item>
<price>4</price>
</items>
<items>
<item>Bag</item>
<price>13</price>
</items>
</supplier>
<supplier>
<supplierid>1002</supplierid>
<totalprice>26</totalprice>
<items>
<item>Sharpner Box</item>
<price>7</price>
</items>
<items>
<item>Pen</item>
<price>4</price>
</items>
<items>
<item>Bag</item>
<price>15</price>
</items>
</supplier>
</products>
I need to take output like below using xsl 1.0 or 2.0
<products>
<supplier>
<supplierid>1001</supplierid>
<totalprice>23</totalprice>
<items>
<item>Pencil</item>
<price>8</price>
</items>
<items>
<item>Pen</item>
<price>5</price>
</items>
<items>
<item>Bag</item>
<price>10</price>
</items>
</supplier>
<supplier>
<supplierid>1001</supplierid>
<totalprice>24</totalprice>
<items>
<item>Paper Box</item>
<price>7</price>
</items>
<items>
<item>Pen</item>
<price>4</price>
</items>
<items>
<item>Bag</item>
<price>13</price>
</items>
</supplier>
<supplier>
<supplierid>1002</supplierid>
<totalprice>26</totalprice>
<items>
<item>Sharpner Box</item>
<price>7</price>
</items>
<items>
<item>Pen</item>
<price>4</price>
</items>
<items>
<item>Bag</item>
<price>15</price>
</items>
</supplier>
</products>
Sort less price from "same suppliers" for example <supplierid>1001</supplierid>
Based on there sub nodes <items>
1001/23 and 1001/30 is same based on there <items><item>. we need to remove 1001/30 from the list. because it is high price
Based on the assumption that you like to sort suppliers based on their totalprice:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:template match="/">
<products>
<xsl:for-each select="products/supplier">
<xsl:sort select="totalprice" data-type="number" order="ascending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</products>
</xsl:template>
</xsl:transform>
This will first sort based on supplierid and secondly based on their totalprice
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()">
<xsl:sort select="supplierid"/> <!-- 1st level sorting -->
<xsl:sort select="totalprice"/> <!-- 2nd level sorting -->
<xsl:sort select="price"/> <!-- 3rd level sorting -->
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note: You can use a free online tool called Online XSLT Test Tool to test your xml/xslt files.