使用XSL移动从一个节点到另一个
所以我想下面使用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>
转换为该
<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>
基本上,我想借此级别的属性,让他们自己事情。如果有某种方法可以删除级别号码并使用节点的顺序来代表这一点,那么将会带来巨大的好处。
这里的解决方案:
<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"]
输入丢失。
可能是一个简单的方法:
<?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>
只是一个变种:
<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>
很好的实施。 – Mic 2011-05-17 07:36:42
这仅仅是使用更短和更简单的解决方案模板(无<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>
当应用o n中提供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。我徘徊了一段时间没有'xsl:for-each'的解决方案。 – 2011-05-17 21:20:18
@empo:谢谢:仅当需要将当前文档更改为另一个文档时,才使用'
听起来很简单!我将在下次考虑使用循环。 – 2011-05-17 21:39:29
我看不到任何东西...... – 2011-05-16 19:12:28
如果您可以添加样本以及最终结果的样本,那将有助于我们帮助您。 – 2011-05-16 19:12:57
好问题,+1。看到我的答案是一个完整的,简短的,基于模板的解决方案 - 这可能是所有答案中最短,最简单和最容易扩展的。 – 2011-05-17 13:40:47