XSLT 2.0:如何替换()部分元素的值并在select操作中使用结果?

时间:2013-08-09 21:39:08

标签: xslt xpath

我在C ++和C#应用程序中做了一些XPath,但这是我第一次在XSLT中直接使用它。我有一个格式如下的XML文件:

<topLevel>
  <foo>
    <bar>prefix1_Taxi</bar>
    ...
  </foo>
  <foo>
    <bar>prefix1_SchoolBus</bar>
    ...
  </foo>
  ...
  <foo>
    <bar>prefix2_Taxi</bar>
    ...
  </foo>
  <foo>
    <bar>prefix2_SchoolBus</bar>
    ...
  </foo>
</topLevel>

首先,我想只选择<foo>元素,其中<bar>元素以“prefix1_”开头。这似乎有效:

<xsl:for-each select="foo[bar[starts-with(., 'prefix1_')]]">

   <!-- Style and format the values from child elements of the "prefix1_" <foo> -->

</xsl:for-each>

for-each块内部,我想要选择包含相应“prefix2_”元素的<foo>元素。然后,我想在我认为合适的情况下从每个数据中提取数据。

例如,当for-each选择了“prefix1_Taxi”时,我想选择包含“prefix2_Taxi”foo元素的bar元素。

<xsl:for-each select="foo[bar[starts-with(., 'prefix1_')]]">

   <!-- Retrieve the corresponding "prefix2_" foo -->
   <!-- Style and format the values from child elements of the "prefix1_" <foo> -->
   <!-- Style and format the values from child elements of the "prefix2_" <foo> -->

</xsl:for-each>

不幸的是,我不知道如何解决这个问题。在传统的程序中,我会做类似下面的伪代码:

String buf = barElement.Name.Replace("prefix1_", String.Empty);
XmlNode otherFoo = document.SelectSingleNode("foo[bar[" + buf + "]]");

然而,XSLT显然可以使用不同的范例来检索值和操作数据,因此我试图摆脱旧的思维模式。

使用我在谷歌搜索中搜索的一些搜索,我想出了一些非常难看的东西:

  1. 选择包含以某些文本开头的小节的foo元素:

    foo[bar[starts-with(., ...)

  2. 替换当前<bar>元素中的“prefix1_”:

    replace(<xsl:value-of select='bar'/>, 'prefix1_', '')

  3. 这会产生一个非常难看的混乱:

    <xsl:value-of select="foo[bar[starts-with(., replace(<xsl:value-of select='bar'/>, 'prefix1_', ''))]]" />
    

    我也很确定<xsl:value-of>元素不正确。

    我该如何解决这个问题?我怀疑我缺少一些如何在XSLT中表达这个概念的核心概念。我正在使用XSLT上的w3.org page,但我还需要进行更多的学习和练习。

2 个答案:

答案 0 :(得分:2)

此XSL样式表应该为您对包含“prefix2”的foo元素所做的操作提供一些灵活性。

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

  <!-- Matches the top level element and selects the children with prefix1 text. -->
  <xsl:template match="topLevel">
    <xsl:copy>
      <xsl:apply-templates select="foo[bar[starts-with(., 'prefix1_')]]"/>
    </xsl:copy>
  </xsl:template>

  <!-- We're at a foo element with prefix1 text. Select the siblings of the 
       same vehicle type, with prefix2 text. -->
  <xsl:template match="foo[bar[starts-with(., 'prefix1_')]]">
    <xsl:variable name="vehicle" select="substring-after(bar, 'prefix1_')"/>
    <xsl:apply-templates select="../foo[bar = concat('prefix2_', $vehicle)]"/>
  </xsl:template>

  <!-- In this template, you can do whatever you want with the foo element containing
       the prefix2 vehicles. This example just copies the element and its children. -->
  <xsl:template match="foo[bar[starts-with(., 'prefix2_')]]">
    <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

<xsl:for-each select="foo[bar[starts-with(., 'prefix1_')]]">
    <xsl:variable name="new-text" as=xs:string" select="replace(bar/text(), '1', '2')" />
    <xsl:value-of select="concat(../foo/bar[$new-text]/text(), ' OR DO SOMETHING MORE USEFUL THAN APPENDING TEXT')" />  
</xsl:for-each>

你在循环中包含“prefix1”文本的foo元素,然后更改为其他bar元素的文本并对其进行操作,无论你想做什么。

备注:您可能需要将xmlns:xs="http://www.w3.org/2001/XMLSchema"添加到XSLT根元素中,以使我的示例中的xs:string生效。并且可能它也可以在没有中间变量的情况下工作,但我认为它使代码更具可读性。