I am trying to sort the E1EDK33 element by "TSRFO_CONSIGNEE" However when doing so I get the original E1EDK33 elements plus the newly sorted elements in the end.
Here is my example file:
<SHPMNT06>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20 SEGMENT="1">
<DeliveryStops>6</DeliveryStops>
<E1EDT22 SEGMENT="1">
<VSART_BEZ>LKW</VSART_BEZ>
</E1EDT22>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<TSRFO>0001</TSRFO>
<TSRFO_CONSIGNEE>0003</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<TSRFO>0002</TSRFO>
<TSRFO_CONSIGNEE>0002</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0003</TSNUM>
<TSRFO>0003</TSRFO>
<TSRFO_CONSIGNEE>0001</TSRFO_CONSIGNEE>
</E1EDK33>
<E1ETD01 SEGMENT="1">
<DGMDDAT>20220321</DGMDDAT>
</E1ETD01>
</E1EDT20>
</IDOC>
</SHPMNT06>
my xslt file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="xml"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="E1EDT20">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="*"/>
<xsl:apply-templates select="E1EDK33">
<xsl:sort select="TSRFO_CONSIGNEE" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result file:
<SHPMNT06>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20 SEGMENT="1">
<DeliveryStops>6</DeliveryStops>
<E1EDT22 SEGMENT="1">
<VSART_BEZ>LKW</VSART_BEZ>
</E1EDT22>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<TSRFO>0001</TSRFO>
<TSRFO_CONSIGNEE>0003</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<TSRFO>0002</TSRFO>
<TSRFO_CONSIGNEE>0002</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0003</TSNUM>
<TSRFO>0003</TSRFO>
<TSRFO_CONSIGNEE>0001</TSRFO_CONSIGNEE>
</E1EDK33>
<E1ETD01 SEGMENT="1">
<DGMDDAT>20220321</DGMDDAT>
</E1ETD01>
<E1EDK33 SEGMENT="1">
<TSNUM>0003</TSNUM>
<TSRFO>0003</TSRFO>
<TSRFO_CONSIGNEE>0001</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<TSRFO>0002</TSRFO>
<TSRFO_CONSIGNEE>0002</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<TSRFO>0001</TSRFO>
<TSRFO_CONSIGNEE>0003</TSRFO_CONSIGNEE>
</E1EDK33>
</E1EDT20>
</IDOC>
</SHPMNT06>
What I want to see is this:
<SHPMNT06>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20 SEGMENT="1">
<DeliveryStops>6</DeliveryStops>
<E1EDT22 SEGMENT="1">
<VSART_BEZ>LKW</VSART_BEZ>
</E1EDT22>
<E1EDK33 SEGMENT="1">
<TSNUM>0003</TSNUM>
<TSRFO>0003</TSRFO>
<TSRFO_CONSIGNEE>0001</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<TSRFO>0002</TSRFO>
<TSRFO_CONSIGNEE>0002</TSRFO_CONSIGNEE>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<TSRFO>0001</TSRFO>
<TSRFO_CONSIGNEE>0003</TSRFO_CONSIGNEE>
</E1EDK33>
<E1ETD01 SEGMENT="1">
<DGMDDAT>20220321</DGMDDAT>
</E1ETD01>
</E1EDT20>
</IDOC>
</SHPMNT06>
I have tried to exclude E1EDK33 from the select <xsl:apply-templates select="*"/> like this: <xsl:apply-templates select="*/*[not(E1EDK33)]"/> and a lot of other permutations but I can't seem to get rid of the duplicated E1EDK33. Either it completely messes up my file or it duplicates it.
You could do
<xsl:template match="E1EDT20">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="E1EDK33[1]/preceding-sibling::*"/>
<xsl:apply-templates select="E1EDK33">
<xsl:sort select="TSRFO_CONSIGNEE" data-type="number" order="ascending"/>
</xsl:apply-templates>
<xsl:apply-templates select="E1EDK33[last()]/following-sibling::*"/>
</xsl:copy>
</xsl:template>
To exclude E1EDK33 elements in your select statement, you could use the self axis like so: *[not(self::E1EDK33)]
Related
I am trying to output this entire XML but with the EVENT elements sorted by ID. Being new to XSLT I thought I would still give it a try but after many attempts and reading other examples and how to guides I still can't get what I thought was a simple thing to work.
<?xml version="1.0" encoding="UTF-8"?>
<PublishWCWORKORDEROUT xmlns="http://www.xcessteel.com/maxo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creationDateTime="2021-05-10T08:23:18+00:00" transLanguage="EN" baseLanguage="EN" messageID="3116171.1620634998889850919" maxoVersion="7 6 20190514-1348 V7611-365" event="1">
<WCWORKORDEROUTSet>
<WORKORDER action="Replace">
<ACTCATEGORY />
<X_3857>1.1838832494481975E7</X_3857>
<Y_3857>-2766476.1752903816</Y_3857>
<SPEC>
<ALNVALUE />
<REFID xsi:nil="true" />
<ASSETATTRID>ACCOUNT_NO</ASSETATTRID>
<CHANGEBY>ADMIN</CHANGEBY>
</SPEC>
<SPEC>
<ALNVALUE />
<REFID xsi:nil="true" />
</SPEC>
<SPEC>
<ALNVALUE />
<REFID xsi:nil="true" />
<ASSETATTRID>METER_LOCATION</ASSETATTRID>
</SPEC>
<EVENT>
<ID>CCC333</ID>
<WORKTYPE>UNPLANNED</WORKTYPE>
</EVENT>
<EVENT>
<ID>AAA111</ID>
<WORKTYPE>PLANNED</WORKTYPE>
</EVENT>
<EVENT>
<ID>BBB222</ID>
<WORKTYPE>SCHEDULED</WORKTYPE>
</EVENT>
<ASSIGNMENT>
<AMCREW />
<WPLABORID>209336</WPLABORID>
</ASSIGNMENT>
<WCWODETAILS>
<REFID xsi:nil="true" />
<CUSTOMERNAME />
<WCREGION>SWR</WCREGION>
<ID>96057400</ID>
</WCWODETAILS>
</WORKORDER>
</WCWORKORDEROUTSet>
</PublishWCWORKORDEROUT>
I have tried with this XSLT but clearly it is not correct.
<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"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/PublishWCWORKORDEROUT">
<xsl:copy>
<xsl:apply-templates select="EVENT">
<xsl:sort select="ID"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You have to declare the namespace xmlns="http://www.xcessteel.com/maxo" and then use that prefix in your match and the sorting could be done like this:
EDIT on 2021-05-24 on 10:19: attribute action="Replace" was missing
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:maxo="http://www.xcessteel.com/maxo"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="maxo:WORKORDER">
<xsl:copy>
<!-- Following line was missing -->
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="maxo:EVENT[1]/preceding-sibling::*"/>
<xsl:apply-templates select="maxo:EVENT">
<xsl:sort select="maxo:ID"/>
</xsl:apply-templates>
<xsl:apply-templates select="maxo:EVENT[ position()=last()]/following-sibling::*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And as an alternative, the following would work as well:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:maxo="http://www.xcessteel.com/maxo"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="maxo:EVENT[not(preceding-sibling:: maxo:EVENT)]">
<xsl:for-each select=".|following-sibling:: maxo:EVENT">
<xsl:sort select="maxo:ID"/>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<xsl:template match="maxo:EVENT[ preceding-sibling:: maxo:EVENT]"/>
</xsl:stylesheet>
I have a XML file which looks roughly like this (actual file is much more complex, everything has been truncated in this example):
<?xml version="1.0" encoding="utf-8"?>
<root>
<element>
<tag1>1</tag1>
<tag2>stuff</tag2>
<type>String</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>2</tag1>
<tag2>stuff</tag2>
<type>String</type>
<type>Date</type>
<type>Float</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>3</tag1>
<tag2>stuff</tag2>
<type>DateTime</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>4</tag1>
<tag2>stuff</tag2>
<type>Float</type>
<type>String</type>
<type>Date</type>
<tag3>stuff</tag3>
</element>
</root>
I process it with the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type"><xsl:call-template name="type"/></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
And I get this resulting file:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:float"/>
My problem here is that only the first <type> tag is taken into account. What I would like is to concatenate all the type tag contents into the type tag of the output, preceded by a sign indicating that the tag is an agglomerate if applicable.
However, to avoid creating artificially numerous types, the content of the tags must be alphabetically sorted first. In this example, the <element> number 2 and 4 are both made of only Float, String, and Date, albeit in a different order. They need to have the same type in the output.
The following output would be acceptable:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
I am very new to XLST, and I have not managed to get anywhere close to the desired output so far. The code I have tried is just below, and fails horribly, notably because I failed to understand how to get <xsl:sort> working:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:apply-templates>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:call-template name="type"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:choose>
<xsl:when test="following-sibling::type">
<xs:text>union</xs:text>
<xsl:for-each select="following-sibling::type">
<xs:text>translate(type,' ','')</xs:text>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Just a few adjustments on your existing code were needed.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:variable name="sorted">
<xsl:for-each select="type">
<xsl:sort select="."/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select="$sorted/type"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="type">
<xsl:variable name="initialType" select="translate(., ' ', '')"/>
<xsl:if test="count(preceding-sibling::type) = 0 and count(following-sibling::type) > 0">
<xsl:text>union</xsl:text>
</xsl:if>
<!-- HINT remove if you dont want any seperator -->
<xsl:if test="count(preceding-sibling::type) > 0">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Please verify, for me i get the output (see HINT inline in XSLT):
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>
I would do it like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:apply-templates select="type">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'String']">xs:string</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Date']">xs:date</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'DateTime']">xs:dateTime</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Float']">xs:float</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Integer']">xs:int</xsl:template>
<xsl:template match="type">
<xsl:value-of select="translate(., ' ', '')"/>
</xsl:template>
</xsl:stylesheet>
I have the below input XML,
for some reason my xslt is not able to sort it.
please advice.
appreciate your insights.
this is the full XML
......................................................
I want to sort the G_SHL segment with its content based on D_628 field.
`<?xml version="1.0" encoding="UTF-8"?>
<LIST>
<S_ISA>
<D_I01>00</D_I01>
<D_I02/>
<D_I03>00</D_I03>
<D_I04/>
<D_I05>01</D_I05>
<D_I06></D_I06>
<D_I05_2>ZZ</D_I05_2>
<D_I07></D_I07>
<D_I08>160427</D_I08>
<D_I09>1106</D_I09>
<D_I10>U</D_I10>
<D_I11>00401</D_I11>
<D_I12>000000001</D_I12>
<D_I13>0</D_I13>
<D_I14/>
<D_I15>></D_I15>
<S_GS>
<D_479>SH</D_479>
<D_142></D_142>
<D_124></D_124>
<D_373>20160427</D_373>
<D_337>1106</D_337>
<D_28>1</D_28>
<D_455>X</D_455>
<D_480>004010</D_480>
<S_ST>
<D_143>856</D_143>
<D_329>0001</D_329>
<S_BSN>
<D_353>00</D_353>
<D_396>0081664420</D_396>
<D_373>20160426</D_373>
<D_337>1347</D_337>
<D_1005>0001</D_1005>
</S_BSN>
<G_SHL>
<S_HL>
<D_628>0000001</D_628>
<D_734>0000000</D_734>
<D_735>S</D_735>
<S_PRF>
<D_324>SITT10-1447195769627</D_324>
<D_328>SITT10-1447195769627</D_328>
</S_PRF>
<S_MEA>
<D_737>PD</D_737>
<D_738>G</D_738>
<D_739>0.081</D_739>
<C_C001>
<D_355>KG</D_355>
</C_C001>
</S_MEA>
<S_TD1>
<D_103>PKG</D_103>
<D_80>00002</D_80>
<D_187>G</D_187>
<D_81>00000.18</D_81>
<D_355>LB</D_355>
</S_TD1>
<S_TD5>
<D_133>O</D_133>
<D_66>2</D_66>
<D_368>CC</D_368>
</S_TD5>
<S_REF>
<D_128>WH</D_128>
<D_127>WH:</D_127>
</S_REF>
<S_REF>
<D_128>RN</D_128>
<D_127>RN:</D_127>
</S_REF>
<S_DTM>
<D_374>011</D_374>
<D_373>20160414</D_373>
</S_DTM>
<G_SN1>
<S_N1>
<D_98>ST</D_98>
<D_93>C3333</D_93>
<S_N3>
<D_166>TEST</D_166>
</S_N3>
<S_N4>
<D_19>TEST</D_19>
<D_116>12345</D_116>
<D_26>US</D_26>
</S_N4>
</S_N1>
</G_SN1>
</S_HL>
</G_SHL>
<G_SHL>
<S_HL>
<D_628>0000002</D_628>
<D_734>0000001</D_734>
<D_735>O</D_735>
<S_MAN>
<D_88>CP</D_88>
<D_87></D_87>
</S_MAN>
</S_HL>
</G_SHL>
<G_SHL>
<S_HL>
<D_628>0000003</D_628>
<D_734>0000002</D_734>
<D_735>P</D_735>
</S_HL>
</G_SHL>
<G_SHL>
<S_HL>
<D_628>0000005</D_628>
<D_734>0000002</D_734>
<D_735>P</D_735>
</S_HL>
</G_SHL>
<G_SHL>
<S_HL>
<D_628>0000004</D_628>
<D_734>0000003</D_734>
<D_735>I</D_735>
<S_LIN>
<D_350>000010</D_350>
<D_235>SK</D_235>
<D_234></D_234>
<D_235_2>BP</D_235_2>
<D_234_2></D_234_2>
</S_LIN>
<S_SN1>
<D_350></D_350>
<D_382>2.000</D_382>
<D_355>EA</D_355>
<D_668>AC</D_668>
</S_SN1>
</S_HL>
</G_SHL>
<G_SHL>
<S_HL>
<D_628>0000006</D_628>
<D_734>0000005</D_734>
<D_735>I</D_735>
<S_LIN>
<D_350>000020</D_350>
<D_235></D_235>
<D_234></D_234>
<D_235_2>BP</D_235_2>
<D_234_2></D_234_2>
</S_LIN>
<S_SN1>
<D_382>1.000</D_382>
<D_355>EA</D_355>
<D_668>AC</D_668>
</S_SN1>
</S_HL>
</G_SHL>
<S_CTT>
<D_354>1</D_354>
</S_CTT>
<S_SE>
<D_96>[]</D_96>
<D_329>0001</D_329>
</S_SE>
</S_ST>
<S_GE>
<D_97>0</D_97>
<D_28>1</D_28>
</S_GE>
</S_GS>
<S_IEA>
<D_I16>01</D_I16>
<D_I12>000000001</D_I12>
</S_IEA>
</S_ISA>
</LIST>`
Try
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/LIST/S_ISA/S_GS/S_ST">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="G_SHL">
<xsl:sort select="S_HL/D_628" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
I can't verify the path /LIST/S_ISA/S_GS/S_ST but assume you have those ancestor elements in your real XML.
If there can be sibling elements you want to keep in their original input position then one way in XSLT 2.0 is to first identify the adjacent elements you want to sort with for-each-group group-adjacent:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/LIST/S_ISA/S_GS/S_ST">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="*" group-adjacent="boolean(self::G_SHL)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()">
<xsl:sort select="S_HL/D_628" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"></xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
In Xpath how would I get my results to select all documents and display them like
<Document>
<Size>100</Size>
<Offset>200</Offset>
<FileName>x.doc</FileName>
</Document>
from
<Documents>
<Document>
<Size>100</Size>
<Offset>200</Offset>
<FileName>x.doc</FileName>
<Details>
<Header>asdfasdf</Header>
<Footer>adfasdfas</Footer>
<Author>asdfasdfs</Author>
<Date>20140101</Date>
</Details>
<Document>
</Documents>
Thanks.
With XSLT you get the result with
<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="//Documents//*">
<xsl:if test="local-name(parent::*)!='Details' and local-name(.) != 'Details'">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
So you would get a copy of all Documents excluding the Details.
For debugging purposes it would be handy to output the full path of the context node from within a template, is there unabbreviated xpath or function to report this ?
Example Template:
<xsl:template match="#first">
<tr>
<td>
<xsl:value-of select="??WHAT TO PUT IN HERE??"/>
</td>
</tr>
</xsl:template>
Example (Abridged) input document:
<people>
<person>
<name first="alan">
...
The output from the template would be something like:
people / person / name / #first
Or something similar.
This transformation produces an XPath expression for the wanted node:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:variable name="vNode" select=
"/*/*[2]/*/#first"/>
<xsl:apply-templates select="$vNode" mode="path"/>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:variable name="vnumFollSiblings" select=
"count(following-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings or $vnumFollSiblings">
<xsl:value-of select=
"concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
</xsl:template>
<xsl:template match="#*" mode="path">
<xsl:apply-templates select="ancestor::*" mode="path"/>
<xsl:value-of select="concat('/#', name())"/>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<people>
<person>
<name first="betty" last="jones"/>
</person>
<person>
<name first="alan" last="smith"/>
</person>
</people>
the wanted, correct result is produced:
/people/person[2]/name/#first
Here's a stylesheet (of dubious value) that prints the path to every element and attribute in a document:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:strip-space elements="*" />
<xsl:template match="*">
<xsl:param name="pathToHere" select="''" />
<xsl:variable name="precSiblings"
select="count(preceding-sibling::*[name()=name(current())])" />
<xsl:variable name="follSiblings"
select="count(following-sibling::*[name()=name(current())])" />
<xsl:variable name="fullPath"
select="concat($pathToHere, '/', name(),
substring(concat('[', $precSiblings + 1, ']'),
1 div ($follSiblings or $precSiblings)))" />
<xsl:value-of select="concat($fullPath, '
')" />
<xsl:apply-templates select="#*|*">
<xsl:with-param name="pathToHere" select="$fullPath" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="#*">
<xsl:param name="pathToHere" select="''" />
<xsl:value-of select="concat($pathToHere, '/#', name(), '
')" />
</xsl:template>
</xsl:stylesheet>
When applied to this input:
<people>
<person>
<name first="betty" last="jones" />
</person>
<person>
<name first="alan" last="smith" />
</person>
<singleElement />
</people>
Produces:
/people
/people/person[1]
/people/person[1]/name
/people/person[1]/name/#first
/people/person[1]/name/#last
/people/person[2]
/people/person[2]/name
/people/person[2]/name/#first
/people/person[2]/name/#last
/people/singleElement