所以我想使用XSL转换以下内容
<doc>
<data id="priority" level="2" include="true">
<name>Priority</name>
</data>
<data id="cost" level="1" leveltype="number">
<name>Cost</name>
</data>
<data id="date" level="3" include="true">
<name>Date</name>
</data>
</doc>
到此
<doc>
<data id="priority">
<name>Priority</name>
</data>
<data id="cost">
<name>Cost</name>
</data>
<data id="date">
<name>Date</name>
</data>
<!-- ordering matters, though if necessary I can reorder this manually via the DOM instead of XSL -->
<levels>
<level id="cost" include="false" type="number"/>
<level id="priority" include="true"/>
<level id="date" include="true"/>
</level>
</doc>
基本上我想采用关卡属性并将它们作为自己的东西。如果有某种方法可以删除级别编号并使用节点的顺序来代表它,那将是一个巨大的好处。
答案 0 :(得分:3)
这是一种仅使用模板的简短解决方案(无<xsl:for-each>
):
<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="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<doc>
<xsl:apply-templates select="*"/>
<levels>
<xsl:apply-templates select="data" mode="level">
<xsl:sort select="@level" data-type="number"/>
</xsl:apply-templates>
</levels>
</doc>
</xsl:template>
<xsl:template match="data/@*[not(name()='id')]"/>
<xsl:template match="data" mode="level">
<level id="{@id}" include="{boolean(@include)}">
<xsl:if test="@leveltype">
<xsl:attribute name="type"><xsl:value-of select="@leveltype"/></xsl:attribute>
</xsl:if>
</level>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<doc>
<data id="priority" level="2" include="true">
<name>Priority</name>
</data>
<data id="cost" level="1" leveltype="number">
<name>Cost</name>
</data>
<data id="date" level="3" include="true">
<name>Date</name>
</data>
</doc>
产生了想要的正确结果:
<doc>
<data id="priority">
<name>Priority</name>
</data>
<data id="cost">
<name>Cost</name>
</data>
<data id="date">
<name>Date</name>
</data>
<levels>
<level id="cost" include="false" type="number"/>
<level id="priority" include="true"/>
<level id="date" include="true"/>
</levels>
</doc>
<强>解释强>:
使用和覆盖身份规则/模板。
使用mode="level"
生成结果文档的第二部分。
答案 1 :(得分:2)
只是一个变种:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="doc">
<doc>
<!-- build and sort data nodes -->
<xsl:for-each select="data">
<xsl:sort select="@id"/>
<data id="{@id}">
<xsl:copy-of select="name"/>
</data>
</xsl:for-each>
<!-- build and sort levels -->
<levels>
<xsl:for-each select="data">
<xsl:sort select="@id"/>
<level id="{@id}" include="{boolean(@include)}">
<xsl:if test="@leveltype">
<xsl:attribute name="type">
<xsl:value-of select="@leveltype"/>
</xsl:attribute>
</xsl:if>
</level>
</xsl:for-each>
</levels>
</doc>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
以下是解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- attribute suppression template -->
<xsl:template match="@*" priority="2"/>
<xsl:template match="/doc">
<xsl:copy>
<xsl:apply-templates select="*" mode="data"/>
<levels>
<xsl:apply-templates select="*" mode="levels">
<xsl:sort select="@level" data-type="number"/>
</xsl:apply-templates>
</levels>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" mode="data">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="data"/>
</xsl:copy></xsl:template><!-- identity template -->
<xsl:template match="@*" mode="data"/><!-- suppress -->
<xsl:template match="@id" mode="data" priority="2"><!-- keep -->
<xsl:copy-of select="."/></xsl:template>
<xsl:template match="@*|node()" mode="levels">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="levels"/>
</xsl:copy></xsl:template><!-- identity template -->
<xsl:template match="data" mode="levels">
<level>
<xsl:apply-templates select="@*" mode="levels"/>
</level></xsl:template>
<xsl:template match="@level" mode="levels"/><!-- suppress -->
<xsl:template match="@leveltype" mode="levels"><!-- rename -->
<xsl:attribute name="type"><xsl:value-of select="."/>
</xsl:attribute></xsl:template>
</xsl:stylesheet>
我假设您预期输出中的<level id="cost" include="false" type="number"/>
是复制/粘贴工件,因为输入中的level[@id="cost"]
缺少该属性。
答案 3 :(得分:0)
可能是一种更简单的方式:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<doc>
<xsl:for-each select="doc/data">
<data>
<xsl:attribute name="id">
<xsl:value-of select="@id"/>
</xsl:attribute>
<name><xsl:value-of select="name" /></name>
</data>
</xsl:for-each>
<levels>
<xsl:for-each select="doc/data">
<xsl:sort select="@level" />
<level>
<xsl:attribute name="id">
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:choose>
<xsl:when test="@include='true'">
<xsl:attribute name="include">true</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="include">false</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</level>
</xsl:for-each>
</levels>
</doc>
</xsl:template>
</xsl:stylesheet>