【问题标题】:combining two elements into one element XSLT将两个元素合并为一个元素 XSLT
【发布时间】:2014-06-16 18:35:13
【问题描述】:

我有这个 xml:

<root>

    <first>The first</first>

    <second>and the second</second>
</root>

我希望输出是:

<root>

     <firstAndSecond>The first and the second</firstAndSecond>

</root>

但是我找不到任何文章来演示如何在 xsl 中执行此操作,因此如果有人可以为我提供示例或链接我解释如何执行此操作的文章,我将非常感激。

提前致谢。

【问题讨论】:

  • 如果 root 元素下有 3 个元素,您希望发生什么?另外,您真的希望将文本也从输出中删除吗?
  • 根元素下永远不会有 3 个元素,第一个 xml 将始终采用该格式。哎呀,我编辑了问题以包含文本。
  • 查看这个旧的 StackOverflow 问题,其中包含指向有用教程和书籍的链接; stackoverflow.com/questions/3511759/…(它因与 StackOverflow 无关而关闭,但答案可能会给您一些想法)。

标签: xml xslt transformation


【解决方案1】:

虽然在这样一个简单的输入 XML 中可能并不完全需要,但通常值得从 XSLT identity transform 开始,它自己复制节点,这意味着您只需要为“异常”编写模板

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

在您的情况下,您可以将问题视为将根的第一个子元素转换为新元素,因此您将有一个模板来匹配第一个元素

 <xsl:template match="/*/*[1]">

要创建具有动态名称的新元素,请使用 xsl:element 命令,如下所示

<xsl:element name="{local-name()}And{local-name(following-sibling::*[1])}">

或者为了保持可读性,在表达式中使用变量

    <xsl:variable name="second" select="local-name(following-sibling::*[1])" />
    <xsl:element name="{local-name()}And{$second}">

注意这里使用了Attribute Value Templates,它表示要计算的表达式,而不是字面输出。因此,在这种情况下,local-name() 被评估以获取元素的名称(不包括命名空间)。

在此您将使用 xsl:apply-templates 复制两个子元素的子元素(这将处理存在要复制的文本以外的节点的情况)

        <xsl:apply-templates select="node()" />
        <xsl:text> </xsl:text>
        <xsl:apply-templates select="following-sibling::*[1]/node()"/>

最后,要停止身份转换复制它,您还需要一个模板来排除 root

的第二个孩子
<xsl:template match="/*/*[position() > 1]" />

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

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

    <xsl:template match="/*/*[1]">
        <xsl:variable name="second" select="local-name(following-sibling::*[1])" />
        <xsl:element name="{local-name()}And{$second}">
            <xsl:apply-templates select="node()" />
            <xsl:text> </xsl:text>
            <xsl:apply-templates select="following-sibling::*[1]/node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="/*/*[position() > 1]" />
</xsl:stylesheet>

注意,这不会将第一个字母大写。为此(在 XSLT 1.0 中),您需要结合使用 substring 提取第一个字母,并使用 translate 将其转换为大写。

【讨论】:

  • 非常感谢,感谢您的详细解释+1。
【解决方案2】:

这个解决方案怎么样?

<root>
    <first>The first</first>
    <second>and the second</second>
</root>
<xsl:template match="root">
    <xsl:variable name="first_name" select="name(*[position() = 1])"/>
    <xsl:variable name="second_name" select="name(*[position() = 2])"/>
    <xsl:variable name="combined_names" select="concat($first_name,'And',$second_name)"/>
    <xsl:element name="{$combined_names}">
        <xsl:value-of select="concat(*[position() = 1],' and ',*[position() = 2])"/>
    </xsl:element>
</xsl:template>

【讨论】:

  • 第十行不能是&lt;xsl:value-of select="concat($first_name,' and ',$second_name)"/&gt;
  • 对不起,没有。我看到 $first_name 和 $last_name 是元素的名称,而不是这些元素的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
  • 1970-01-01
  • 2014-08-02
  • 1970-01-01
  • 2018-11-27
  • 2016-07-25
  • 1970-01-01
相关资源
最近更新 更多