Xml XSLT将元素替换为其父元素的名称
我是一名XSLT开发人员,正在尝试进行以下转换: 资料来源:Xml XSLT将元素替换为其父元素的名称,xml,xslt,Xml,Xslt,我是一名XSLT开发人员,正在尝试进行以下转换: 资料来源: ... <student> <item> <contact> <item> <phone>000000001</phone> </item> <item> <phone>
...
<student>
<item>
<contact>
<item>
<phone>000000001</phone>
</item>
<item>
<phone>000000002</phone>
</item>
</contact>
<name>John</name>
</item>
<item>
<name>Francis</name>
</item>
</student>
...
结果:
...
<student>
<contact>
<phone></phone>
</contact>
<contact>
<phone></phone>
</contact>
<name>John</name>
</student>
<student>
<name>Francis</name>
</student>
...
我想用父元素的名称替换每个元素项,然后删除它们自己的父元素
到目前为止,我得到的是:
<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="item">
<xsl:element name="{parent::*/name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
方向正确吗?方向是正确的,从父元素检索元素名是个好主意,但是
<xsl:apply-templates select=".."/>
样式表
XML输出
如果规则仅依赖于元素的层次结构,请尝试以下样式表。它没有提到任何具体的元素名称
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" 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="/*/*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/*/*/*">
<xsl:element name="{parent::*/name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:transform>
XML输出
编辑
使用@Ian的建议:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" 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="*[*][not(*[not(self::item)])]">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="item">
<xsl:element name="{parent::*/name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:transform>
XML输出
方向是正确的,从父元素检索元素名是一个好主意,但是
<xsl:apply-templates select=".."/>
样式表
XML输出
如果规则仅依赖于元素的层次结构,请尝试以下样式表。它没有提到任何具体的元素名称
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" 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="/*/*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/*/*/*">
<xsl:element name="{parent::*/name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:transform>
XML输出
编辑
使用@Ian的建议:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" 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="*[*][not(*[not(self::item)])]">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="item">
<xsl:element name="{parent::*/name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:transform>
XML输出
这是Matthias优秀答案的延伸
从你对另一个答案的评论来看:
此父级/项结构可以位于较大文档中的任何位置
item元素始终被称为item,但父元素可以被称为任何东西
另一个答案给出了您需要的基本逻辑-一个处理大多数事情的标识模板,一个匹配只应用模板的父级的模板,以及一个匹配从父级获取元素名称的项的模板-但是如果我们不知道父级的名称,我们如何匹配父级?那么,这个怎么样:
<xsl:template match="*[*][not(*[not(self::item)])]">
<xsl:apply-templates />
</xsl:template>
这将匹配所有子元素都命名为item的任何元素。双负表示没有名称不是item的子元素,但这将包括一个没有子元素的元素的情况,因此初始[*]必须确保至少有一个子元素。这是Matthias优秀答案的扩展
从你对另一个答案的评论来看:
此父级/项结构可以位于较大文档中的任何位置
item元素始终被称为item,但父元素可以被称为任何东西
另一个答案给出了您需要的基本逻辑-一个处理大多数事情的标识模板,一个匹配只应用模板的父级的模板,以及一个匹配从父级获取元素名称的项的模板-但是如果我们不知道父级的名称,我们如何匹配父级?那么,这个怎么样:
<xsl:template match="*[*][not(*[not(self::item)])]">
<xsl:apply-templates />
</xsl:template>
这将匹配所有子元素都命名为item的元素。双负数表示没有名称不是item的子元素,但这将包括没有子元素的元素的情况,因此必须使用首字母[*],以确保至少有一个子元素。问题需要更多信息。根节点呢?是否也要对根节点执行相同的操作?如果这样做,最终会生成无效的XML..我更新了原始帖子。根元素旁边永远不会有item元素。该问题需要更多信息。根节点呢?是否也要对根节点执行相同的操作?如果这样做,最终会生成无效的XML..我更新了原始帖子。根元素旁边永远不会有item元素。谢谢您的回复。问题是我不知道该项的父项名称,这意味着我无法匹配它。@sovesky然后请查看第二个样式表-我已经编辑了我的答案。谢谢。我快到了。我更新了原来的帖子。代码可以工作,但不适用于嵌套项结构。@sovesky再次编辑了我的答案,合并了Ian建议的模板。@sovesky如果最终证明您确实需要XSLT 1.0而不是2.0,那么您需要在样式表中更改的唯一一件事就是用name替换parent:::*/name。谢谢您的回复。问题是我不知道该项的父项名称,这意味着我无法匹配它。@sovesky然后请查看第二个样式表-我已经编辑了我的答案。谢谢。我快到了。我更新了原来的帖子。代码可以工作,但不适用于嵌套项结构。@sovesky再次编辑了我的答案,合并了Ian建议的模板。@sovesky如果最终证明您确实需要XSLT 1.0而不是2.0,那么您需要在样式表中更改的唯一一件事就是用name替换parent:::*/name。我仍然认为xpath中有一个很大的遗漏,无法指定一个元素,其中所有子元素都匹配一个模式,而不是任何子元素。不幸的是,双负数是必需的,如果括号错误,通常很难调试。@Flynn1179给出的问题是XSLT 2.0没有明确提到,但您可以从../name中看出,您可以将其写为[every$n in*满足$n/name eq‘item’]啊。。不幸的是,我太习惯XSLT1了。几乎无法使用MSXSL或浏览
我在做变换。但情况未必如此——有可能OP没有意识到这在XSLT1中不起作用,毕竟这不起作用。@flyn1179确实如此。当你第一次看到这个双重否定的习语时,它看起来有点奇怪,但它只是一个习语,一旦你习惯了它,你就可以识别它的意思,而不必每次都对它进行解码。+1这是一个有用的扩展,可以将逻辑应用到层次结构中的任何地方。我仍然认为这是xpath中的一个重大遗漏,无法指定一个元素,其中所有子元素都匹配一个模式,而不是任何子元素。不幸的是,双负数是必需的,如果括号错误,通常很难调试。@Flynn1179给出的问题是XSLT 2.0没有明确提到,但您可以从../name中看出,您可以将其写为[every$n in*满足$n/name eq‘item’]啊。。不幸的是,我太习惯XSLT1了。在我所在的地方,我一直在使用MSXSL或浏览器进行转换。但情况未必如此——有可能OP没有意识到这在XSLT1中不起作用,毕竟这不起作用。@flyn1179确实如此。当你第一次看到这个双重否定的习语时,它看起来有点奇怪,但它只是一个习语,一旦你习惯了它,你就可以识别它的意思,而不必每次都对它进行解码。
<xsl:template match="*[*][not(*[not(self::item)])]">
<xsl:apply-templates />
</xsl:template>