使用匹配特定选择器的 XSL 对 XML 进行排序并保持 XML 相同
Sort XML with XSL matching specific selectors and keep XML the same
我正在尝试使用 XSLT 1.0
对我的 XML 进行仅排序转换。除了 order/sequence.
之外,我不需要对转换后的 XML 进行任何更改
我创建了一个精简版的 XML,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<mpcconfiguration>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
以下是需要重点关注的重要方面:
- 根元素将始终是
mpcconfiguration
。
- 我需要在
mpcconfiguration
下方对 <lineitem>
元素进行相对排序。
- 排序顺序应由
/mpcconfiguration/lineitem/category@id=Mstr_Information/option@id=Mstr_Information/property@id=Mstr_ModelSortOrder
的值驱动(该伪代码用简单的英语表示:“按 <property>
的值排序,其 id
是 Mstr_ModelSortOrder
,其父对象是 ID 为 Mstr_Information
的 <option>
,其父对象为 ID 为 Mstr_Information
的 <category>
,其父对象为 <lineitem>
")
- 请注意具有 555、777 和 999 等值的
<property
元素。出于排序目的,可以忽略这些元素,因为它们的祖先与我在 #3 中描述的模式不匹配。所有这些数据仍然必须在转换后的 XML 中,但这些与排序无关。
- 每个
<lineitem>
中只有一个 <property id="Mstr_ModelSortOrder">XXX</property>
的祖先符合上述第 3 条所述的模式。
这是 desired/transformed XML 如果我尝试计算的 XSL 行为正确:
<?xml version="1.0" encoding="UTF-8"?>
<mpcconfiguration>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
请注意,2 个 xml 示例是相同的,只是 <lineitem>
节点的顺序不同,排序依据:
<property id="Mstr_ModelSortOrder">1</property>
<property id="Mstr_ModelSortOrder">2</property>
<property id="Mstr_ModelSortOrder">3</property>
这是我对 xsl 的微弱尝试,尽管它不正确:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="no" />
<xsl:template match="/">
<xsl:copy-of select="*" />
</xsl:template>
<xsl:template match="mpcconfiguration">
<xsl:copy>
<xsl:apply-templates select="//mpcconfiguration/category/option/property">
<xsl:sort select="@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我知道上面有相当数量的 XML 和 XSL,但总结非常简单:按 Mstr_ModelSortOrder
XML [= 对所有 <lineitem>
节点进行排序21=],只要 属性 在 XML 树上有正确的祖先。
此 XSLT 1.0 转换可执行您描述的操作
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="mpcconfiguration">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="lineitem">
<xsl:sort select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']" data-type="number" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出:
<?xml version="1.0" encoding="utf-8"?>
<mpcconfiguration>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
模板 #1 是身份模板。它匹配任何不匹配更具体模板的节点,并将其逐字复制到输出。
模板 #2 是唯一更具体的模板 - 它只匹配 <mpcconfiguration>
,复制它,并为任何属性节点 @*
调用匹配的模板(恰好有 none 在你的输入样本中)和任何 <lineitem>
children,按它们各自的 <property id="Mstr_ModelSortOrder">
排序。这些节点的唯一匹配模板是身份模板,它完成它的工作并按原样复制它们。
<xsl:strip-space elements="*" />
是为了方便,用<xsl:output indent="yes" />
.
实现漂亮的输出
较短的版本假定 <mpcconfiguration>
是 top-level 元素,并使用 <xsl:for-each>
:
复制 <lineitem>
children
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/mpcconfiguration">
<xsl:copy>
<xsl:for-each select="lineitem">
<xsl:sort select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']" data-type="number" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我正在尝试使用 XSLT 1.0
对我的 XML 进行仅排序转换。除了 order/sequence.
我创建了一个精简版的 XML,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<mpcconfiguration>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
以下是需要重点关注的重要方面:
- 根元素将始终是
mpcconfiguration
。 - 我需要在
mpcconfiguration
下方对<lineitem>
元素进行相对排序。 - 排序顺序应由
/mpcconfiguration/lineitem/category@id=Mstr_Information/option@id=Mstr_Information/property@id=Mstr_ModelSortOrder
的值驱动(该伪代码用简单的英语表示:“按<property>
的值排序,其id
是Mstr_ModelSortOrder
,其父对象是 ID 为Mstr_Information
的<option>
,其父对象为 ID 为Mstr_Information
的<category>
,其父对象为<lineitem>
") - 请注意具有 555、777 和 999 等值的
<property
元素。出于排序目的,可以忽略这些元素,因为它们的祖先与我在 #3 中描述的模式不匹配。所有这些数据仍然必须在转换后的 XML 中,但这些与排序无关。 - 每个
<lineitem>
中只有一个<property id="Mstr_ModelSortOrder">XXX</property>
的祖先符合上述第 3 条所述的模式。
这是 desired/transformed XML 如果我尝试计算的 XSL 行为正确:
<?xml version="1.0" encoding="UTF-8"?>
<mpcconfiguration>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
请注意,2 个 xml 示例是相同的,只是 <lineitem>
节点的顺序不同,排序依据:
<property id="Mstr_ModelSortOrder">1</property>
<property id="Mstr_ModelSortOrder">2</property>
<property id="Mstr_ModelSortOrder">3</property>
这是我对 xsl 的微弱尝试,尽管它不正确:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="no" />
<xsl:template match="/">
<xsl:copy-of select="*" />
</xsl:template>
<xsl:template match="mpcconfiguration">
<xsl:copy>
<xsl:apply-templates select="//mpcconfiguration/category/option/property">
<xsl:sort select="@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我知道上面有相当数量的 XML 和 XSL,但总结非常简单:按 Mstr_ModelSortOrder
XML [= 对所有 <lineitem>
节点进行排序21=],只要 属性 在 XML 树上有正确的祖先。
此 XSLT 1.0 转换可执行您描述的操作
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="mpcconfiguration">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="lineitem">
<xsl:sort select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']" data-type="number" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出:
<?xml version="1.0" encoding="utf-8"?>
<mpcconfiguration>
<lineitem id="1">
<seriesdesc>series2</seriesdesc>
<modeldesc>model2</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">1</property>
</option>
</category>
<category id="Category2">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">999</property>
</option>
</category>
</lineitem>
<lineitem id="2">
<seriesdesc>series3</seriesdesc>
<modeldesc>model3</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">2</property>
</option>
</category>
<category id="Category3">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">555</property>
</option>
</category>
</lineitem>
<lineitem id="0">
<seriesdesc>series1</seriesdesc>
<modeldesc>model1</modeldesc>
<labels>
<label id="ExtPrice">Extended Price</label>
</labels>
<category id="Mstr_Information">
<description>Model Information</description>
<option id="Mstr_Information">
<description>descr1</description>
<unitprice>0</unitprice>
<property id="ExtPrice">0</property>
<property id="Mstr_ModelSortOrder">3</property>
</option>
</category>
<category id="Category1">
<description>a cool category</description>
<option id="option123">
<description>a cool option</description>
<unitprice>0</unitprice>
<property id="Mstr_ModelSortOrder">777</property>
</option>
</category>
</lineitem>
</mpcconfiguration>
模板 #1 是身份模板。它匹配任何不匹配更具体模板的节点,并将其逐字复制到输出。
模板 #2 是唯一更具体的模板 - 它只匹配 <mpcconfiguration>
,复制它,并为任何属性节点 @*
调用匹配的模板(恰好有 none 在你的输入样本中)和任何 <lineitem>
children,按它们各自的 <property id="Mstr_ModelSortOrder">
排序。这些节点的唯一匹配模板是身份模板,它完成它的工作并按原样复制它们。
<xsl:strip-space elements="*" />
是为了方便,用<xsl:output indent="yes" />
.
较短的版本假定 <mpcconfiguration>
是 top-level 元素,并使用 <xsl:for-each>
:
<lineitem>
children
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/mpcconfiguration">
<xsl:copy>
<xsl:for-each select="lineitem">
<xsl:sort select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']" data-type="number" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>