【问题标题】:Getting values from nodes when the XPath itself is a text inside a node当 XPath 本身是节点内的文本时从节点获取值
【发布时间】:2011-04-13 18:26:18
【问题描述】:

简单的问题:我有一个这样的 XML 文件:

<Locations>
    <Location>/Simulation/@ID</Location>
    <Location>/Simulation/Loans</Location>
    <Location>/Simulation/Assets</Location>
    <Location>/Simulation/BankAssets</Location>
    <Location>/Simulation/RealEstates</Location>
</Locations>

我还有第二个 XML 文件,其中包含与这些 XPath 节点匹配的数据。而且我需要创建一个没有任何脚本的 XSLT 1.0 可以转换此数据文件以生成与这些节点匹配的数据列表。像这样的:

<Data>
    <Item Node="/Simulation/@ID">
        <Value>1</Value>
        <Value>2</Value>
        <Value>3</Value>
    </Item>
    <Item Node="/Simulation/Loans">
        <Value>1024</Value>
        <Value>555</Value>
        <Value>0</Value>
    </Item>
</Data>

每个项目的值节点数量并不重要。不同项目的值之间的关系也不重要。基本上,样式表只是为了收集简单的统计数据,以进行总结、平均等等。 van 的位置列表变化很大,具体取决于用户想要什么。这个例子只是一些恶搞数据。

问题:如何收集这些信息?

【问题讨论】:

标签: xslt xslt-1.0


【解决方案1】:

实际上有两种方法——一种是进行两相变换,另一种是使用evaluate扩展函数。

两相变换

首先您需要根据您的Locations 列表生成正确的XSL。它可能看起来像这样:

<xsl:template match="/">
    <Data>
        <Item Node="/Simulation/@ID">
            <xsl:apply-templates select="/Simulation/@ID"/>
        </Item>
        <Item Node="/Simulation/Loans">
            <xsl:apply-templates select="/Simulation/Loans"/>
        </Item>

        <!-- ... and so on ... -->

    </Data>
</xsl:template>

<xsl:template match="node()|@*">
    <Value>
        <xsl:value-of select="."/>
    </Value>
</xsl:template>

我假设您在创建将根据您的 XPath 定义文件生成此输出的转换时没有太多麻烦,因为模式非常简单。

下一步是将生成的转换应用到您的源文件。您可以将这两个步骤组合成小管道并获得您想要的结果。

使用扩展功能

库 EXSLT 包含名为 evaluate 的扩展函数,可在像您这样的情况下提供帮助。开箱即用的 Xalan 变压器支持它,但据我所知,撒克逊人不支持它。 然而,这个函数有一个主要问题——从 Xalan 的 2.7 版开始,有一个 bug 可以防止执行多个评估。不幸的是,当我尝试运行它时,下面的样式表受到了影响。如果可能,建议将 Xalan 的版本更改为 2.6。不过,这里的样式表无需额外的生成阶段即可满足您的需求。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">

    <xsl:variable name="locations" select="document('xpath.xml')/Locations"/>
    <xsl:variable name="root" select="/"/>

    <xsl:template match="/">
        <Data>
            <xsl:for-each select="$locations/Location">
                <Item Node="{.}">
                    <xsl:variable name="currentLocation" select="concat('$root', .)"/>
                    <xsl:apply-templates select="dyn:evaluate($currentLocation)"/>
                </Item>
            </xsl:for-each>
        </Data>
    </xsl:template>

    <xsl:template match="node()|@*">
        <Value>
            <xsl:value-of select="."/>
        </Value>
    </xsl:template>

</xsl:stylesheet>

假设具有 Locations 定义的文档位于同一目录中,名为xpath.xml。如果不是这样,请更新 document() 函数用法。

【讨论】:

  • 还有仅 XSLT 1.0 实现的简单 XPath 表达式“walker”模板,就像我在问题评论中发布的模板一样。
  • 不幸的是,EXSLT 是没有选择的。
猜你喜欢
  • 2015-03-08
  • 2012-12-30
  • 2014-01-14
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多