XSLT用它的父级名称替换元素

时间:2014-10-24 09:14:34

标签: xml xslt

我是一名尝试进行以下转换的XSLT开发人员:

来源:

...
<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>

...

我想用它的父级名称替换每个元素“item”,然后删除它们自己的父级。

这是我到目前为止所得到的:

<?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>

我是朝着正确的方向前进的吗?

2 个答案:

答案 0 :(得分:3)

方向是正确的,从父级检索元素名称是个好主意,但是

<xsl:apply-templates select=".."/>

接下来将处理父元素的节点。但是,您应该继续处理item元素的内容。

如果删除parent元素,那么结果显然是格式错误的XML。所以我假设以下XML输入(所有内容都包含root元素):

XML输入

<root>
<parent>
    <item>
        <val1>...</val1>
        <val2>...</val2>
    </item>
    <item>
        <val2>...</val2>
    </item>
</parent>
</root>

<强>样式表

<?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="parent">
            <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="item">
        <xsl:element name="{parent::*/name()}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:transform>

XML输出

<root>
   <parent>
      <val1>...</val1>
      <val2>...</val2>
   </parent>
   <parent>
      <val2>...</val2>
   </parent>
</root>

如果规则仅依赖于元素的层次结构,请尝试以下样式表。它没有提到任何具体的元素名称。

<?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输出

<root>
   <parent>
      <val1>...</val1>
      <val2>...</val2>
   </parent>
   <parent>
      <val2>...</val2>
   </parent>
</root>

编辑

使用@ 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输出

<student>
   <contact>
      <phone>000000001</phone>
   </contact>
   <contact>
      <phone>000000002</phone>
   </contact>
   <name>John</name>
</student>
<student>
   <name>Francis</name>
</student>

答案 1 :(得分:2)

这是Matthias

的优秀答案的延伸

从您对其他答案的评论看起来像:

  • 此父/项结构可以是更大文档中的任何位置
  • “item”元素始终称为item,但“parent”元素可以被称为任何内容

另一个答案提供了您需要的基本逻辑 - 一个处理大多数事情的身份模板,一个匹配刚刚执行apply-templates的父模板的模板和一个匹配带有元素名称的item的模板来自父母 - 但如果我们不知道它的名字,我们如何匹配父母?那么,这个怎么样:

<xsl:template match="*[*][not(*[not(self::item)])]">
    <xsl:apply-templates />
</xsl:template>

这将匹配其子项 all 名为item的任何元素(双重否定表示“没有名称不是项目的子元素”,但这将包括案例一个没有子元素的元素,所以初始[*]是确保至少有一个子元素所必需的。)