【问题标题】:XSLT 1.0: Howto merge XML nodes, then move attribute to child and change their valuesXSLT 1.0:如何合并 XML 节点,然后将属性移动到子节点并更改它们的值
【发布时间】:2016-08-02 12:34:57
【问题描述】:

我有以下 XML(为清楚起见,省略了一些其他节点、子节点和属性):

<Restriktion Typ="Aussageeinheit">
    <Restriktion Code="49" moreAttributes><moreChildren/></Restriktion>
    <Restriktion Code="10"/>
</Restriktion>
<Restriktion Typ="Plot">
    <Restriktion Code="78"/>
</Restriktion>
<Restriktion Typ="Baum">
    <Restriktion Code="22"/>
</Restriktion>

我想用 XSLT 1.0 将它转换成:

<Restriktionen>
    <Restriktion Code="49" Typ="1" MoreAttributes><MoreChildren/></Restriktion>
    <Restriktion Code="10" Typ="1"/>
    <Restriktion Code="78" Typ="2"/>
    <Restriktion Code="22" Typ="3"/>
</Restriktionen>

例如将父元素 Restriktion 合并到 Restriktionen,将属性 Type 移动到子元素,并将属性值从“Aussageeinheit”更改为 1,从“Plot”更改为 2,从“Baum”更改为 3。

【问题讨论】:

  • 恐怕你遗漏了太多。请显示Restriktion 的父节点好吗?除了Restriktion,还有其他孩子吗?

标签: xml xslt


【解决方案1】:

我相信这样的事情应该适合你:

XSLT 1.0

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

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

<xsl:template match="parent">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(self::Restriktion)]"/>
        <Restriktionen>
            <xsl:apply-templates select="Restriktion/Restriktion"/>
        </Restriktionen>
    </xsl:copy>
</xsl:template>

<xsl:template match="Restriktion">
    <xsl:copy>
        <xsl:attribute name="Typ">
            <xsl:choose>
                <xsl:when test="../@Typ='Aussageeinheit'">1</xsl:when>
                <xsl:when test="../@Typ='Plot'">2</xsl:when>
                <xsl:when test="../@Typ='Baum'">3</xsl:when>
            </xsl:choose>
        </xsl:attribute>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

其中parent 是Restriktion 的父元素(在您的示例中未显示)。


补充:

如果&lt;parent&gt; 的孩子的顺序很重要,那么有 所有孩子都放在孩子面前的问题 &lt;Restriktionen&gt;。有没有办法保持孩子们的秩序?

有几种方法可以保持原始顺序。

最好的方法是在xsl:apply-templates 指令中在&lt;Restriktionen&gt; 之前和之后显式命名其他子节点。

或者,您可以这样做:

XSLT 1.0

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

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

<xsl:template match="Restriktion[1]">
    <Restriktionen>
        <xsl:apply-templates select="../Restriktion/Restriktion" mode="grp"/>
    </Restriktionen>
</xsl:template>

<xsl:template match="Restriktion"/>

<xsl:template match="Restriktion" mode="grp">
    <xsl:copy>
        <xsl:attribute name="Typ">
            <xsl:choose>
                <xsl:when test="../@Typ='Aussageeinheit'">1</xsl:when>
                <xsl:when test="../@Typ='Plot'">2</xsl:when>
                <xsl:when test="../@Typ='Baum'">3</xsl:when>
            </xsl:choose>
        </xsl:attribute>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

请注意,散布在 Restriktion 元素之间的任何子节点都将放置在 &lt;Restriktionen&gt; 块之后(尽管您可以通过选择另一个谓词而不是 [1] 来控制它)。

如果不存在这样的子节点,你也可以这样做:

XSLT 1.0

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

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

<xsl:template match="parent">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates select="Restriktion[1]/preceding-sibling::*"/>
        <Restriktionen>
            <xsl:apply-templates select="Restriktion/Restriktion"/>
        </Restriktionen>
        <xsl:apply-templates select="Restriktion[last()]/following-sibling::*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Restriktion">
    <xsl:copy>
        <xsl:attribute name="Typ">
            <xsl:choose>
                <xsl:when test="../@Typ='Aussageeinheit'">1</xsl:when>
                <xsl:when test="../@Typ='Plot'">2</xsl:when>
                <xsl:when test="../@Typ='Baum'">3</xsl:when>
            </xsl:choose>
        </xsl:attribute>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

【讨论】:

  • 感谢您的帮助,正是我所需要的。
  • 如果 的孩子的顺序很重要,那么就会出现所有孩子都放在孩子 之前的问题。有没有办法保持孩子们的秩序?
  • 你知道这些孩子的名字吗?
  • 是的,但我只是想知道是否有办法不必明确指定它们。如果没有,没问题。
  • @Simon 明确指定它们是最好的方法。有关一些替代方案,请参阅我的答案的补充。
猜你喜欢
  • 2021-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 2021-02-02
  • 1970-01-01
  • 2021-03-14
相关资源
最近更新 更多