So I want to convert the following using XSL
所以我想使用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>
To this
对此
<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>
Basically I want to take the level attributes and make them their own thing. A huge bonus would be if there were some way to remove the level number and use the order of the node instead to represent that.
基本上我想采用关卡属性并使它们成为自己的东西。如果有某种方法可以删除级别编号并使用节点的顺序代替它,那么将会有巨大的好处。
4 个解决方案
#1
3
This is a shorter and simpler solution using only templates (no <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>
When applied on the provided XML document:
应用于提供的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>
the wanted, correct result is produced:
产生了想要的正确结果:
<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>
Explanation:
说明:
-
Using and overriding the identity rule/template.
使用和覆盖标识规则/模板。
-
Using
mode="level"
to generate the second part of the result-document.使用mode =“level”生成结果文档的第二部分。
#2
2
Just a variant:
只是一个变种:
<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>
#3
0
Here's the solution:
这是解决方案:
<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>
I assume that <level id="cost" include="false" type="number"/>
in your expected output is a copy/paste artefact as the attribute is missing from level[@id="cost"]
in the input.
我假设您的预期输出中的
#4
0
May be a simpler way:
可能是一种更简单的方法:
<?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>
#1
3
This is a shorter and simpler solution using only templates (no <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>
When applied on the provided XML document:
应用于提供的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>
the wanted, correct result is produced:
产生了想要的正确结果:
<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>
Explanation:
说明:
-
Using and overriding the identity rule/template.
使用和覆盖标识规则/模板。
-
Using
mode="level"
to generate the second part of the result-document.使用mode =“level”生成结果文档的第二部分。
#2
2
Just a variant:
只是一个变种:
<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>
#3
0
Here's the solution:
这是解决方案:
<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>
I assume that <level id="cost" include="false" type="number"/>
in your expected output is a copy/paste artefact as the attribute is missing from level[@id="cost"]
in the input.
我假设您的预期输出中的
#4
0
May be a simpler way:
可能是一种更简单的方法:
<?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>