xsl:for-each选择唯一的案例

时间:2017-10-13 16:04:54

标签: xml xslt xslt-1.0

我正在使用xslt 1.0将XML转换为PDF。我必须选择覆盖给定条件“IsBeneficialOwner = false”的所有唯一memberId。

<xsl:for-each select="//clientMembers/memberId" >
  <xsl:if test="not(contains(/clientMemberRelations[IsBeneficialOwner='true']/memberId))" >
    <fo:table-row>
      <fo:table-cell xsl:use-attribute-sets="white">
        <fo:block white-space-treatment="preserve"
          ><xsl:value-of select="//clientMembers/memberId"
          /><fo:leader/></fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="white">
        <fo:block white-space-treatment="preserve"
          ><xsl:value-of select="//clientMembers/name/name"
          /><fo:leader/></fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="white">
        <fo:block white-space-treatment="preserve"
          ><xsl:value-of select="//clientMembers/type/memberType"
          /><fo:leader/></fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="white">
        <fo:block white-space-treatment="preserve"
          ><xsl:value-of select="//clientMemberRelations/association/associationToEntity"
          /><fo:leader/></fo:block>
      </fo:table-cell>                    
    </fo:table-row>     
  </xsl:if>
</xsl:for-each>

上面有什么问题不包含条件?我在控制台中收到以下错误 -

  

javax.xml.transform.TransformerException:FuncContains只允许2个参数

示例XML文件位于 -

之下
    <clientMemberRelations>
        <updateSource>xxxxx</updateSource>
        <ownedEntityMemberId>2</ownedEntityMemberId>
        <association>               
            <associationToEntity>Controlling Person </associationToEntity>
        </association>
        <IsBeneficialOwner>true</IsBeneficialOwner>
        <memberId>6</memberId>
    </clientMemberRelations>
     <clientMemberRelations>
        <updateSource>xxxxx</updateSource>
        <ownedEntityMemberId>2</ownedEntityMemberId>
        <association>               
            <associationToEntity>Controlling Person </associationToEntity>
        </association>
        <IsBeneficialOwner>false</IsBeneficialOwner>
        <memberId>4</memberId>
    </clientMemberRelations>
    <clientMembers>
        <address>
            <proofSourceDmcId>0</proofSourceDmcId>
            <postalZipCode>0-0</postalZipCode>
            <updateSource>xxx</updateSource>
            <city>xxx</city>
            <proofSourceDmcVersion>0</proofSourceDmcVersion>
            <stateProvince>xxx</stateProvince>
            <Country>xxxxx</Country>
            <type>xx</type>
            <line1>xxxx</line1>
            <ISOCountry>xxx</ISOCountry>
        </address>          
        <memberId>4</memberId>
    </clientMembers>

如您所见,XML有2个节点clientMemberRelations和clientMembers。 我必须选择clientMembers Nodes中的所有memberId,但是我必须省略那些“IsBeneficialOwner”标志为“true”的memberId。 我尝试了几种xsl:for-each和xsl:variable的组合,但没有得到所需的结果。

请建议是否可以使用XSLT 1.0以及如何实现?

2 个答案:

答案 0 :(得分:0)

您关注的表达方式是

not(contains(/clientMemberRelations[IsBeneficialOwner='true']/memberId))

如果将其分成多行,可能更容易看到问题(这在语法上是正确的XPath,尽管人们可能不会通过查看Web上的示例来了解它。)

not(
  contains(
    /clientMemberRelations[IsBeneficialOwner='true']/memberId
   )
)

你现在看到问题了吗? not函数应该接受一个参数,并在此处获取一个参数。 contains函数需要两个参数(这是您的错误消息所说的内容,但是FuncContains&#39;可能不是最明显的方式来引用contains()函数XPath),但你只给它一个。

从您提供的片段中,如果有问题的成员ID包含某些魔术子字符串,或者如果成员ID包含在包含所有成员列表的某个字符串中,您似乎希望发出表格行要在表中生成行的ID。在第一种情况下,您需要类似

的内容
not(contains(
    /clientMemberRelations[IsBeneficialOwner='true']/memberId,
    $magic-string
   )
)

在第二种情况下,你想要像

这样的东西
not(contains(
    $wanted-list,
    /clientMemberRelations[IsBeneficialOwner='true']/memberId
   )
)

这就是你问的问题的答案。

另一方面,你对这个问题的散文描述暗示了一些完全不同的东西,这需要一个不同的解决方案。这两个分析的唯一共同点是,您似乎需要更好地理解contains()函数的作用(并且您应该知道您想要问什么问题并提出问题)

你说

  

我必须选择覆盖给定条件的所有唯一memberId&#34; IsBeneficialOwner = false&#34;

我认为您的意思是,对于for-each循环中的每个memberId元素,您要检查该成员ID是否显示为集合/clientMemberRelations [IsBeneficialOwner='true'] /memberId中元素的值。最简单的方法是将for-each循环表示为:

<xsl:for-each select="//clientMembers/memberId" >
  <xsl:choose>
    <xsl:when test=". = /clientMemberRelations
                        [IsBeneficialOwner='true'] 
                        /memberId">
      <!--* it's a beneficial owner, no output here! *-->
    </xsl:when>
    <xsl:when test=". = /clientMemberRelations
                        [IsBeneficialOwner='false']
                        /memberId">
      <!--* it's not a beneficial owner, write a row! *-->
      <fo:table-row>
        ...
      </
    </
    <xsl:when test=". = /clientMemberRelations
                        [IsBeneficialOwner]
                        /memberId>
      ... handle the case where there is an `IsBeneficialOwner`
          element but it's neither true nor false ... 
    </
    <xsl:when test=". = /clientMemberRelations
                        [not(IsBeneficialOwner)]
                        /memberId>
      ... handle the case where there is no `IsBeneficialOwner`
          element as sibling of the memberId ... 
          and also the case where there is no such element ...
    </
    <xsl:otherwise>
      ... handle any remaining cases ...  
    </
  </
</

答案 1 :(得分:0)

除了Michael Sperberg-McQueen的评论之外,我只会注意到

<xsl:for-each select="//clientMembers/memberId" >
  <xsl:if test="not(contains(/clientMemberRelations[IsBeneficialOwner='true']/memberId))" >

看起来不对,因为测试表达式对xsl:for-each选择的每个节点都具有相同的值。我认为你几乎肯定希望test属性中的表达式根据上下文项目给出不同的结果,而且这个表达式不会。