XSLT:从源XML节点中获取派生值的最大值

时间:2011-01-13 20:34:50

标签: xml xslt

我有一个XML结构,如下所示

<Categories>
<cat>Video</cat>
<cat>Audio</cat>
<cat>Hybrid</cat>
</Categories>

在这样的查找XML中有一个可用于此类别的映射

<Lookup>
<cat>Video</cat>
<mapping>1</mapping>
</Lookup>
<Lookup>
<cat>Audio</cat>
<mapping>2</mapping>
</Lookup>
<Lookup>
<cat>Hybrid</cat>
<mapping>3</mapping>
</Lookup>
</ValueSet>

现在我正在寻找一个XSLT解决方案,它可以在不使用节点集扩展功能的情况下将Max值作为输出返回给我。

以下是我的测试用例

测试案例1:

输入:

<Categories>
<cat>Video</cat>
<cat>Audio</cat>
<cat>Hybrid</cat>
</Categories>

预期产出3

测试案例2:

输入:

<Categories>
<cat>Video</cat>
<cat>Hybrid</cat>
</Categories>

预期产出3

测试案例3:

输入:

<Categories>
<cat>Video</cat>
<cat>Audio</cat>
</Categories>

预期产出2

测试案例4:

输入:

<Categories>
<cat>Audio</cat>
<cat>Hybrid</cat>
</Categories>

预期产出3

测试案例5:

输入:

<Categories>
<cat>Video</cat>
</Categories>

预期产出1

提前致谢。

从评论中更新

  

查找我的信息不是   可以加载[使用document()   功能]。我需要for-each   类别输入然后导出   查找值。在那之后,我需要   获得最大化。

     

我有xsl提供的扩展程序   引擎处理器来实现这一点   xslt如下:

<xsl:value-of select='xx:lookupValue("MappingXML","Category",.,"COL1")'/>
     

此函数返回字符串。这个   函数不返回nodeset。一世   通过捕获所有来尝试变量   执行后的派生值   for-each,但需要进一步处理   这个变量输出(RTF),在XSLt中   1.0,我没有处理任何node-set()函数。

3 个答案:

答案 0 :(得分:2)

来自OP的评论

  

我有xsl提供的扩展程序   引擎处理器来实现这一点   xslt如下:<xsl:value-of select='xx:lookupValue("MappingXML","Category",.,"COL1")'/>    - satish

这适用于XSLT 2.0并且必须在XSLT 1.0中工作(只需删除<xsl:function>并使用您的扩展功能):

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xx="my:xx"
 >
 <xsl:output omit-xml-declaration="yes"/>

 <xx:lookup>
    <ValueSet>
        <Lookup>
            <cat>Video</cat>
            <mapping>1</mapping>
        </Lookup>
        <Lookup>
            <cat>Audio</cat>
            <mapping>2</mapping>
        </Lookup>
        <Lookup>
            <cat>Hybrid</cat>
            <mapping>3</mapping>
        </Lookup>
    </ValueSet>
 </xx:lookup>

 <xsl:variable name="vlookupDoc" select="document('')/*/xx:lookup"/>

    <xsl:template match="/*">
      <xsl:call-template name="getMax">
        <xsl:with-param name="pNodes" select="cat"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="getMax">
      <xsl:param name="pcurrMax" select="-9999999999"/>
      <xsl:param name="pNodes"/>

      <xsl:choose>
       <xsl:when test="not($pNodes)">
         <xsl:value-of select="$pcurrMax"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:variable name="vNewVal" select=
         "number(xx:lookupValue($vlookupDoc,$pNodes[1]))"/>
         <xsl:call-template name="getMax">
          <xsl:with-param name="pNodes" select="$pNodes[position() >1]"/>
          <xsl:with-param name="pcurrMax" select=
           "number(($pcurrMax >= $vNewVal))*$pcurrMax
           +
            number(($vNewVal > $pcurrMax))*$vNewVal"/>
         </xsl:call-template>
       </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

    <xsl:function name="xx:lookupValue">
      <xsl:param name="pLookupDoc"/>
      <xsl:param name="pCat"/>

      <xsl:value-of select=
        "$pLookupDoc/*/*[cat=$pCat]/mapping"/>
    </xsl:function>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<Categories>
    <cat>Video</cat>
    <cat>Audio</cat>
    <cat>Hybrid</cat>
</Categories>

产生了想要的正确结果

3

转换为XSLT 1.0的代码

<xsl:stylesheet version="12.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xx="Your Namespace Here"
 >
 <xsl:output omit-xml-declaration="yes"/>

 <xx:lookup>
    <ValueSet>
        <Lookup>
            <cat>Video</cat>
            <mapping>1</mapping>
        </Lookup>
        <Lookup>
            <cat>Audio</cat>
            <mapping>2</mapping>
        </Lookup>
        <Lookup>
            <cat>Hybrid</cat>
            <mapping>3</mapping>
        </Lookup>
    </ValueSet>
 </xx:lookup>

 <!-- You probably don't need this and the above embedded XML -->
 <xsl:variable name="vlookupDoc" select="document('')/*/xx:lookup"/>

    <xsl:template match="/*">
      <xsl:call-template name="getMax">
        <xsl:with-param name="pNodes" select="cat"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="getMax">
      <xsl:param name="pcurrMax" select="-9999999999"/>
      <xsl:param name="pNodes"/>

      <xsl:choose>
       <xsl:when test="not($pNodes)">
         <xsl:value-of select="$pcurrMax"/>
       </xsl:when>
       <xsl:otherwise>
       <!-- Change the call of the ext. function as appr. -->
         <xsl:variable name="vNewVal" select=
         "number(xx:lookupValue($vlookupDoc,$pNodes[1]))"/>
         <xsl:call-template name="getMax">
          <xsl:with-param name="pNodes" select="$pNodes[position() >1]"/>
          <xsl:with-param name="pcurrMax" select=
           "($pcurrMax >= $vNewVal)*$pcurrMax
           +
            ($vNewVal > $pcurrMax)*$vNewVal"/>
         </xsl:call-template>
       </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

这是XSLT的经典最大算法:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xx="extension-URI">
    <xsl:template match="/">
        <xsl:for-each select="Categories/cat">
            <xsl:sort select="xx:lookupValue('MappingXML',
                                             'Category',
                                             .,
                                             'COL1')"
                      data-type="number"
                      order="descending"/>
            <xsl:if test="position()=1">
                <xsl:value-of select="xx:lookupValue('MappingXML',
                                                     'Category',
                                                     .,
                                                     'COL1')"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

当然,你的限制和映射强制这个添加一个额外调用扩展函数...如果这是一个很大的代价,你应该逐个节点地递归(或者在下面的兄弟轴上进行交叉)解决方案,如@Dimitre。

在XPath / XSLT 2.0中,它更容易:

max(Categories/cat/xx:lookupValue('MappingXML','Category',.,'COL1')

答案 2 :(得分:0)

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

    <xsl:template match="/*">
        <xsl:variable name="docLookup" select="document('lookup_file.xml')/*/Lookup"/>
        <xsl:variable name="avElms" select="cat"/>
        <xsl:value-of select="$docLookup/mapping
                            [not(. &lt; ../../Lookup[cat = $avElms]/mapping)]/text()"/>
    </xsl:template>
</xsl:stylesheet>

结果:

<Categories>
    <cat>Video</cat>
    <cat>Audio</cat>
    <cat>Hybrid</cat>
</Categories>

结果为3

<Categories>
    <cat>Video</cat>
    <cat>Hybrid</cat>
</Categories>

结果为3

<Categories>
    <cat>Video</cat>
    <cat>Audio</cat>
</Categories>

结果为2

<Categories>
    <cat>Audio</cat>
    <cat>Hybrid</cat>
</Categories>

结果为3

<Categories>
    <cat>Video</cat>
</Categories>

结果为1