在单个XPath表达式中转换xsl:for-each

时间:2014-08-18 12:52:54

标签: xslt xpath xslt-1.0

我想过滤元素集合(菜单项)。 我是为每个人做的。它看起来像这样:

<xsl:variable name="actualMenus">
 <xsl:for-each select="$menus">
  <xsl:variable name ="startDate" select="current()/cs:Properties/cs:CommercePropertyItem[cs:Key='StartDate']/cs:Value"/>
  <xsl:variable name ="endDate" select="current()/cs:Properties/cs:CommercePropertyItem[cs:Key='EndDate']/cs:Value"/>
  <xsl:variable name="today" select="translate(substring-before($menuDate, 'T'), '-', '')"/>
  <xsl:variable name="start" select="translate(substring-before($startDate, 'T'), '-', '')"/>
  <xsl:variable name="end" select="translate(substring-before($endDate, 'T'), '-', '')"/>

  <xsl:if test="$start &lt;= $today and $today &lt;= $end">
    <child>
      <xsl:value-of select="current()"/>
    </child>
  </xsl:if>
 </xsl:for-each>
</xsl:variable>

然后我通过以下代码使用它:     msxsl:node-set($actualMenus)/child

我尝试用xpath表达式替换上面的代码:

<xsl:variable name="actualMenus" 
     select="$menus[translate(substring-before(current()/cs:Properties/cs:CommercePropertyItem[cs:Key='StartDate']/cs:Value, 'T'), '-', '') &lt;= translate(substring-before($menuDate, 'T'), '-', '') 
                and translate(substring-before($menuDate, 'T'), '-', '') &lt;= translate(substring-before(current()/cs:Properties/cs:CommercePropertyItem[cs:Key='EndDate']/cs:Value, 'T'), '-', '')]" />

不幸的是,它没有用。

有人可以帮我找出xpath表达式中的错误吗?

1 个答案:

答案 0 :(得分:0)

您的代码的主要问题是您没有显示上下文(请参阅上面的评论,请更新您的问题)。但是,我的猜测是问题在于current()。在xsl:for-each中,current - 函数指向for-each正在处理的当前节点。在新的select-expression中,current - 函数指向 XPath表达式的上下文节点。它没有指向$menus中的当前项,您应该使用上下文项表达式.(尽管在您的情况下它是多余的)。

我通过添加看似可能的输入文档来尝试您的代码(再次,请用它更新您的问题!)。如果运行以下样式表,则会为两个xsl:value-of指令输出相同的样式表。您可以针对任何输入文档运行样式表,它只需要变量$menus(我将其包装在node-set中)。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:cs="http://whatever/cs"
    xmlns:ext="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="ext cs"
    version="1.0">

    <xsl:output indent="yes" omit-xml-declaration="yes" />

    <xsl:variable name="menuDate" select="'2014-08-14T03:44'" />
    <xsl:variable name="menus" >
        <cs:Properties>
            <cs:CommercePropertyItem>
                <cs:Key>StartDate</cs:Key>
                <cs:Value>2014-03-04T12:38</cs:Value>
            </cs:CommercePropertyItem>
            <cs:CommercePropertyItem>
                <cs:Key>EndDate</cs:Key>
                <cs:Value>2014-12-04T12:38</cs:Value>
            </cs:CommercePropertyItem>
        </cs:Properties>
    </xsl:variable>

    <xsl:template match="/" >
        <xsl:variable name="actualMenus">
            <xsl:for-each select="ext:node-set($menus)">
                <xsl:variable name ="startDate" select="current()/cs:Properties/cs:CommercePropertyItem[cs:Key='StartDate']/cs:Value"/>
                <xsl:variable name ="endDate" select="current()/cs:Properties/cs:CommercePropertyItem[cs:Key='EndDate']/cs:Value"/>
                <xsl:variable name="today" select="translate(substring-before($menuDate, 'T'), '-', '')"/>
                <xsl:variable name="start" select="translate(substring-before($startDate, 'T'), '-', '')"/>
                <xsl:variable name="end" select="translate(substring-before($endDate, 'T'), '-', '')"/>

                <xsl:if test="$start &lt;= $today and $today &lt;= $end">
                    <child>
                        <xsl:value-of select="current()"/>
                    </child>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>

        <!-- output text value of actual menu -->
        <xsl:value-of select="$actualMenus" />
        <xsl:text>&#xa;</xsl:text>

        <!-- output text value of actual menu using single XPath -->
        <xsl:value-of select="ext:node-set($menus)
            [
                translate(substring-before(cs:Properties/cs:CommercePropertyItem[cs:Key='StartDate']/cs:Value, 'T'), '-', '') 
                &lt;= translate(substring-before($menuDate, 'T'), '-', '') 
                and 
                translate(substring-before($menuDate, 'T'), '-', '') 
                &lt;= translate(substring-before(cs:Properties/cs:CommercePropertyItem[cs:Key='EndDate']/cs:Value, 'T'), '-', '')
            ]" />
    </xsl:template>

</xsl:stylesheet>

将输出:

StartDate2014-03-04T12:38EndDate2014-12-04T12:38
StartDate2014-03-04T12:38EndDate2014-12-04T12:38

您的表达与我的表达之间的区别在于我从您的表达式中删除了current()。事实证明,在你的for-each循环中,这也是多余的,因为默认情况下获取焦点的节点与current()返回的节点相同(但不要忘记删除领先斜线)。

我不确定为什么你希望它是一个单行的XPath。我不认为代码会变得更清晰,但当然,这是一个品味问题。