2011-01-24 79 views
8

我想知道如何在遵守某些条件的情况下使用XSLT将节点向上移动一个级别。举个例子,看看下面的XML源代码:XSLT:将节点向上移动

<Settings> 
    <String [...]> 
    <Boolean [...]/> 
    </String> 
</Settings> 

这就是我作为起始情况的XML。清楚的是,节点名称“Settings”,“String”,“Boolean”是我们定义的特殊节点。

问题是“布尔”节点不允许在“字符串”节点内部。这就是为什么我必须将这些“布尔”节点升级。所需的XML是这样的:

<Settings> 
    <String [...]></String> 
    <Boolean [...]/> 
</Settings> 

的XSLT还拥有具有同级布尔节点,无论在XML树中的位置的每个字符串节点的工作。

到目前为止,我了解到,你必须首先使用“身份规则”拷贝所有的XML,然后运用一些特殊的规则所期望的转变:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"> 

    <!-- Identity rule --> 
    <xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- special rules ... --> 

</xsl:stylesheet> 

我挣扎的东西是规则将所有“布尔”节点(它们是“字符串”节点的同级节点)向上移动一级。我怎样才能做到这一点?!?

+0

好问题,+1。查看我的答案,了解“覆盖身份规则”设计模式的变体 - 我提供了更准确的覆盖。 :) – 2011-01-24 14:17:50

回答

6

我的要求解释给出了解决方案,

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes"/> 

<xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="String"> 
    <xsl:copy> 
     <xsl:apply-templates select="child::node()[not(self::Boolean)]"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 

</xsl:stylesheet> 
3

尝试以下操作:

<!-- copy all --> 
<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<!-- ignore booleans-inside-strings --> 
<xsl:template match="String/Boolean" /> 

<!-- place the booleans-inside-strings into the settings element --> 
<xsl:template match="Settings"> 
    <xsl:copy> 
     <xsl:copy-of select="//String/Boolean" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 
+1

在“全部复制”模板中,为什么不匹配“match =”@ * | node()“`和`select =”@ * | node()“?只是好奇... – Filburt 2011-01-24 09:30:30

+0

谢谢你的回答。这对我的例子很好。但它不会始终工作,因为它总是将布尔节点复制到设置元素中。该规则应该将布尔元素向上复制一层。想想 这应该转化为: Jens 2011-01-24 10:26:27

+0

另外,为什么开始``//在'//字符串/ Boolean`? – 2011-01-24 18:56:12

3

该解决方案是非常相似Michae凯的@。然而,身份规则压倒一切的是多一点点精确的 - 只有String元素真的有Boolean孩子匹配:

<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="String[Boolean]"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()[not(self::Boolean)]|@*"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 
</xsl:stylesheet> 

当这种转变是对下面的XML文档应用:

<Settings> 
    <String> 
     <Boolean /> 
    </String> 
    <String/> 
</Settings> 

想要的,正确的结果产生

<Settings> 
    <String/> 
    <Boolean/> 
    <String/> 
</Settings>