XSLT排序异常:E_E20下非ROOT节点丢失,求修正方案
XSLT排序问题:保留非ROOT节点并按MAT分组排序ROOT节点
需求说明
仅对/HEADER/DOC/E_E20下MAT值相同的ROOT节点,以FIELD3为关键字进行排序,其余节点(如ND2、ND3、L18等)保持原有位置不变。当前编写的XSLT虽能实现排序逻辑,但丢失了E_E20下的非ROOT初始节点。
输入XML
<?xml version="1.0" encoding="UTF-8"?> <HEADER> <DOC BEGIN="1"> <EDI_40> <Field1>123</Field1> </EDI_40> <E_E20> <ND2>123</ND2> <ND3>345</ND3> <L18 SEGMENT="1"> <QUALF>PGI</QUALF> </L18> <ROOT SEGMENT="1"> <POS>000020</POS> <MAT>1234</MAT> <FIELD3>4199</FIELD3> <QUAN>3420</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4199BI015</FIELD3> <QUAN>3420</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN1</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4184AI015</FIELD3> <QUAN>1026</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN2</PQ> </CHILD> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN2</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4200AI015</FIELD3> <QUAN>1197</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN3</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000030</POS> <MAT>123</MAT> <FIELD3>4200AI</FIELD3> <QUAN>1197</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN</PQ> </CHILD> </ROOT> </E_E20> </DOC> </HEADER>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <HEADER> <DOC BEGIN="1"> <EDI_40> <Field1>123</Field1> </EDI_40> <E_E20> <ND2>123</ND2> <ND3>345</ND3> <L18 SEGMENT="1"> <QUALF>PGI</QUALF> </L18> <ROOT SEGMENT="1"> <POS>000020</POS> <MAT>1234</MAT> <FIELD3>4199</FIELD3> <QUAN>3420</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4184AI015</FIELD3> <QUAN>1026</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN2</PQ> </CHILD> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN2</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4199BI015</FIELD3> <QUAN>3420</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN1</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000010</POS> <MAT>123456</MAT> <FIELD3>4200AI015</FIELD3> <QUAN>1197</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN3</PQ> </CHILD> </ROOT> <ROOT SEGMENT="1"> <POS>000030</POS> <MAT>123</MAT> <FIELD3>4200AI</FIELD3> <QUAN>1197</QUAN> <CHILD SEGMENT="1"> <POS>000010</POS> <PQ>UN</PQ> </CHILD> </ROOT> </E_E20> </DOC> </HEADER>
原XSLT代码
<?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:output method="xml" indent="yes"/> <xsl:mode on-no-match="shallow-copy"/> <xsl:template match="E_E20"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:for-each-group select="ROOT" group-by="MAT"> <xsl:apply-templates select="current-group()"> <xsl:sort select="FIELD3"/> </xsl:apply-templates> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
问题原因及解决方案
问题原因
原模板仅处理了E_E20下的ROOT节点,完全忽略了其他子节点(如ND2、ND3、L18),导致这些节点在输出中丢失。
修正后的XSLT代码
<?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:output method="xml" indent="yes"/> <xsl:mode on-no-match="shallow-copy"/> <xsl:template match="E_E20"> <xsl:copy> <xsl:apply-templates select="@* | *[not(self::ROOT)]"/> <!-- 先处理所有非ROOT节点,保留原有位置 --> <xsl:for-each-group select="ROOT" group-by="MAT"> <xsl:apply-templates select="current-group()"> <xsl:sort select="FIELD3"/> </xsl:apply-templates> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
说明
修正后的模板在处理E_E20时,先通过@* | *[not(self::ROOT)]处理所有属性和非ROOT子节点,确保这些节点保留原位置;然后再对ROOT节点按MAT分组,并在每组内按FIELD3排序输出,既满足排序需求,又保留了其他节点。
内容的提问来源于stack exchange,提问作者Anu
相关产品推荐
相关产品推荐

