使用XSL中的"for-each"处理参数栈? [英] Processing stacks of parameters using 'for-each' in XSL?

查看:96
本文介绍了使用XSL中的"for-each"处理参数栈?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在模板中有一系列相互依赖的param元素(即,每个后续的param都使用前一个的值作为XPath的一部分)

例如

<xsl:param name="input1" select="path/node/@value"/>

<xsl:param name="input2" select="path/anothernode[@value=$input1]/anothervalue"/>

<xsl:param name="input3" select="path/thirdnode[@value=$input2]/@endvalue"/>

等等

这些参数堆栈一次即可完美运行.但是,当我使用for-each循环调用模板并使用xsl:with-param将for-each值传递给它时,仅处理顶部参数-该值不会传递给下一个参数.

这是我的完整xsl:

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/" name="test">

  <xsl:param name="memberId"    
    select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value"/>
  <xsl:param name="memberRef" 
    select="PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/>  
  <xsl:param name="memberRef2"    
    select="translate($memberRef,'#','')"/> 
  <xsl:param name="userId"    
    select="PLMXML/User[@id=$memberRef2]/@personRef"/>
  <xsl:param name="userId2"    
    select="translate($userId,'#','')"/>    
  <xsl:param name="personName"    
    select="PLMXML/Person[@id=$userId2]/@lastName"/>
  <xsl:param name="groupRef"    
    select="PLMXML/User[@id=$memberRef2]/UserData/UserValue/@dataRef"/>
  <xsl:param name="groupRef2"    
    select="translate($groupRef,'#','')"/>
  <xsl:param name="groupName"    
    select="PLMXML/Organisation[@id=$groupRef2]/@name"/>
  <xsl:param name="roleRef"    
    select="PLMXML/Organisation[@id=$groupRef2]/UserData/UserValue/@dataRef"/>
  <xsl:param name="roleRef2"    
    select="translate($roleRef,'#','')"/>
  <xsl:param name="roleName"    
    select="PLMXML/Role[@id=$roleRef2]/@name"/>

  <xsl:value-of select="$memberId"/>

  <xsl:value-of select="$memberRef"/>

  <xsl:value-of select="$personName"/>  
  <xsl:value-of select="$groupName"/>
  <xsl:value-of select="$roleName"/>

</xsl:template>

<xsl:template match="/">

  <xsl:for-each select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value">

    <xsl:call-template name="test">

      <xsl:with-param name="memberId" select="."/>

    </xsl:call-template>

  </xsl:for-each>

</xsl:template>


</xsl:stylesheet>

但是,for-each循环仅在模板"test"中填充堆栈的顶部变量-即xsl:value-of select="$memberId"/>有效,但<xsl:value-of select="$memberRef"/>无效.

任何有关如何解决此问题的想法将不胜感激.

解决方案

您遇到的问题是上下文之一.您当前在XML中所处的位置.考虑您的 xsl:for-each 循环

<xsl:for-each select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value">

您正在遍历 @value 属性,这意味着在循环内您位于 @value 属性上,因此,任何相对的xpath表达式都将相对于该属性.当您执行 xsl:call-template 时,您仍将位于 @value 属性上,因此所有 xsl:param 中的xpath表达式strong>陈述将与此相对.

<xsl:param name="memberRef" 
     select="PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/>  

也就是说, select 语句在当前 @value 下寻找一个 PLMXML 元素,该元素显然不存在!

第一个参数 memberId 起作用的原因是因为您向该参数传递了一个明确的值,因此将使用该参数代替 select 中的默认值.属性.所有其他参数将不起作用,因为它们将使用默认值.

解决方案可能是使所有参数都具有绝对表达式,这意味着在它们前面加上/.

<xsl:param name="memberRef" 
     select="/PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/> 

/表示顶级文档节点,因此xpath表达式将相对于该文档,而不是当前节点.

请注意,在这种情况下,您可以考虑使用 xsl:key 查找此类元素.例如

<xsl:key name="OrganisationMember" match="OrganisationMember" use="@id" />

然后param语句变为:

<xsl:param name="memberRef" select="key('OrganisationMember', $memberId)/@memberRef"/> 

顺便说一句,具有两个优先级相同的模板匹配同一事物被认为是错误的.因此,您的第一个命名"模板应该删除了 match 属性.即代替<xsl:template match="/" name="test">,执行此操作

 <xsl:template name="test">

I have a series of param elements inside a template that rely upon each other (i.e. each subsequent param uses the value of the previous one as part of it's XPath)

e.g.

<xsl:param name="input1" select="path/node/@value"/>

<xsl:param name="input2" select="path/anothernode[@value=$input1]/anothervalue"/>

<xsl:param name="input3" select="path/thirdnode[@value=$input2]/@endvalue"/>

etc. etc.

The stack of params works perfectly on a single run through. However, when I use a for-each loop to call the template and pass the for-each value to it using xsl:with-param, only the top param is processed - the value is NOT passed to the next the parameter.

Here's my full xsl:

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/" name="test">

  <xsl:param name="memberId"    
    select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value"/>
  <xsl:param name="memberRef" 
    select="PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/>  
  <xsl:param name="memberRef2"    
    select="translate($memberRef,'#','')"/> 
  <xsl:param name="userId"    
    select="PLMXML/User[@id=$memberRef2]/@personRef"/>
  <xsl:param name="userId2"    
    select="translate($userId,'#','')"/>    
  <xsl:param name="personName"    
    select="PLMXML/Person[@id=$userId2]/@lastName"/>
  <xsl:param name="groupRef"    
    select="PLMXML/User[@id=$memberRef2]/UserData/UserValue/@dataRef"/>
  <xsl:param name="groupRef2"    
    select="translate($groupRef,'#','')"/>
  <xsl:param name="groupName"    
    select="PLMXML/Organisation[@id=$groupRef2]/@name"/>
  <xsl:param name="roleRef"    
    select="PLMXML/Organisation[@id=$groupRef2]/UserData/UserValue/@dataRef"/>
  <xsl:param name="roleRef2"    
    select="translate($roleRef,'#','')"/>
  <xsl:param name="roleName"    
    select="PLMXML/Role[@id=$roleRef2]/@name"/>

  <xsl:value-of select="$memberId"/>

  <xsl:value-of select="$memberRef"/>

  <xsl:value-of select="$personName"/>  
  <xsl:value-of select="$groupName"/>
  <xsl:value-of select="$roleName"/>

</xsl:template>

<xsl:template match="/">

  <xsl:for-each select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value">

    <xsl:call-template name="test">

      <xsl:with-param name="memberId" select="."/>

    </xsl:call-template>

  </xsl:for-each>

</xsl:template>


</xsl:stylesheet>

However, the for-each loop only populates the top variable of the stack in template 'test' - i.e. xsl:value-of select="$memberId"/> works but <xsl:value-of select="$memberRef"/> does not.

Any ideas on how to work around this issue would be much appreciated.

解决方案

The problem you are having is one of context; where you are currently positioned in the XML. Consider your xsl:for-each loop

<xsl:for-each select="PLMXML/Organisation/UserData/UserValue/UserList/Item/@value">

You are looping over @value attributes, meaning within the loop you are positioned on a @value attribute, and consequently any relative xpath expressions will be relative to that. When you do your xsl:call-template you will still be positioned on the @value attribute, and so all the xpath expressions in the xsl:param statements will be relative to that.

<xsl:param name="memberRef" 
     select="PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/>  

That is to say, the select statement is looking for a PLMXML element underneath the current @value, which clearly does not exist!

The reason the first parameter, memberId, works is because you pass an explicit value to that, and so that will be used instead of the default value in the select attribute. All the other parameters will not work because they will use the default value.

The solution is, probably, is to make all your parameters have absolute expressions, which means prefixing them with a /.

<xsl:param name="memberRef" 
     select="/PLMXML/OrganisationMember[@id=$memberId]/@memberRef"/> 

The / represents the top level document node, and so the xpath expression will then be relative to that, and not the current node.

Note, you might consider using xsl:key in this instance to look-up such elements. For example

<xsl:key name="OrganisationMember" match="OrganisationMember" use="@id" />

Then the param statement becomes this:

<xsl:param name="memberRef" select="key('OrganisationMember', $memberId)/@memberRef"/> 

As an aside, it is considered an error to have two templates of equal priority matching the same thing. So, your first 'named' template should probably have the match attribute removed. i.e. Instead of <xsl:template match="/" name="test">, do this

 <xsl:template name="test">

这篇关于使用XSL中的"for-each"处理参数栈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆