【问题标题】:XSL transformation - how to look for linking nodeXSL 转换 - 如何查找链接节点
【发布时间】:2015-05-11 03:36:10
【问题描述】:

我是 XSL 转换的新手。我正在将以下 XML 转换为另一种 XML 格式:

<root>

 <header>
   <section id="a1">
     <color>red</color>
   </section>

   <section id="a2">
     <color>blue</color>
   </section>

 </header>

 <body>
   This is the sample text <reference link="a1">with color red</reference> 
   and <reference link="a2">with color blue</reference>
 </body> 

</root>

部分 id(在标题中)链接到参考链接(在正文中)。我必须在&lt;color&gt; 节点中寻找颜色“蓝色”。如果它可用,那么我必须删除父 &lt;section&gt; 节点。除此之外,该部分的“id”是“a2”。必须删除正文中相应的参考链接。结果:

<root>

 <header>
   <section id="a1">
     <color>red</color>
   </section>

 </header>

 <body>
   This is the sample text <reference link="a1">with color red</reference> 
   and with color blue
 </body> 

</root>

谁能提供一些关于如何开始的提示?

【问题讨论】:

  • 您能使用 XSLT 2.0 还是仅限于 1.0?你想硬编码“蓝色”作为目标还是需要作为参数传入?
  • 服务器有 Java 1.5。它是否支持 XSLT 2.0?你能告诉如何检查版本吗?我想硬编码“蓝色”。
  • @Mahesh:我相信 JDK 1.5 附带了实现 XSLT 1.0 的 Xalan 版本,但您可以轻松切换到 Saxon 并运行 XSLT 2.0。

标签: xml xslt transformation


【解决方案1】:

您应该能够获取具有blue 的部分的@id,然后剥离section 并“解包”reference

这里有 2 个例子。一个在 XSLT 1.0 中,一个在 XSLT 2.0 中。

XSLT 1.0

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

    <xsl:param name="toStrip" select="'blue'"/>
    <xsl:variable name="stripRef" select="//section[color=$toStrip]/@id"/>

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

    <xsl:template match="header">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[not(self::section[@id=$stripRef])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="reference">
        <xsl:choose>
            <xsl:when test="@link=$stripRef">
                <xsl:apply-templates/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

XSLT 2.0

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

    <xsl:param name="toStrip" select="'blue'"/>
    <xsl:variable name="stripRef" select="//section[color=$toStrip]/@id"/>

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

    <xsl:template match="section[@id=$stripRef]"/>

    <xsl:template match="reference[@link=$stripRef]">
        <xsl:apply-templates/>
    </xsl:template>    

</xsl:stylesheet>

根据评论进行编辑

这是处理多个 ID 的一种方法。由于toStrip 参数不能是序列,我们需要添加一个字符来分隔值。在这个例子中,我使用了|。这样在比较 a1a10 之类的内容时,contains() 就不会是真的。

此外,XSLT 1.0 将仅返回 stripRef 变量选择中的第一个 @id。为了获取所有 ID,我添加了一个 xsl:for-each。您也可以使用模式对xsl:apply-templates 执行此操作。

这是更新后的 XSLT:

XSLT 1.0

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

    <xsl:param name="toStrip" select="'|blue|orange|'"/>
    <xsl:variable name="stripRef">
        <xsl:text>|</xsl:text>
        <xsl:for-each select="//section[color[contains($toStrip,concat('|',.,'|'))]]/@id">
            <xsl:value-of select="concat(.,'|')"/>
        </xsl:for-each>
    </xsl:variable>

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

    <xsl:template match="header">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[not(self::section[contains($stripRef,concat('|',@id,'|'))])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="reference">
        <xsl:message>contains(<xsl:value-of select="$stripRef"/>,<xsl:value-of select="concat('|',@link,'|')"/>)</xsl:message>
        <xsl:choose>
            <xsl:when test="contains($stripRef,concat('|',@link,'|'))">
                <xsl:apply-templates/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

要在 XSLT 2.0 中做同样的事情,您只需将 toStrip 参数更改为一个序列:

<xsl:param name="toStrip" select="('blue','orange')"/>

【讨论】:

  • 您可能会发现“2.0”版本实际上适用于您现有的基于 Xalan 的设置 - XSLT 1.0 规范禁止在匹配模式中使用变量引用,但我发现 Xalan 实际上允许至少在某些版本中是这样。
  • @Daniel Haley:非常感谢您的帮助。我还有一个疑问。有没有办法在 StripRef 中获取多个 id?例如,如果我想排除蓝色和橙色。
  • @Mahesh - 是的,这是可能的。这在 2.0 中非常容易。您使用的是 2.0 还是 1.0?
  • @Daniel Haley:我使用的是 1.0
  • @Mahesh - 我为 1.0 和 2.0 添加了示例。如您所见,2.0 要简单得多。
猜你喜欢
  • 1970-01-01
  • 2011-04-13
  • 1970-01-01
  • 2016-06-10
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 2018-03-25
  • 2018-11-17
相关资源
最近更新 更多