xslt转换列表并取最大值

时间:2012-03-06 01:35:21

标签: map transform xslt-1.0

我想:

  1. 选择所有属性“foo”,它们是字符串值,并将值存储在列表中。
  2. 使用我的xslt中的某个地图将此列表中属性“foo”的每个值转换为数字。
  3. 选择列表的最大值并输出。
  4. 所以给出以下xml:

    <t>
        <tag foo="A">apples</tag>
        <tag foo="C">oranges</tag>
        <tag foo="B">trees</tag>
    </t>
    

    以下映射:

    <xsl:variable name="myMap">
        <entry key="A">1</entry>
        <entry key="B">2</entry>
        <entry key="C">3</entry>
    </xsl:variable>
    

    输出结果为:

    <max>3</max>
    

    另一个问题,为什么我不能缩进我的代码?我正在放置空格,但它不起作用。

1 个答案:

答案 0 :(得分:3)

I此标准XSLT 1.0转换(最类似于您的方法):

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

 <xsl:variable name="vrtfMap">
  <entry key="A" value="1"/>
  <entry key="B" value="2"/>
  <entry key="C" value="3"/>
  <entry key="X" value="8"/>
 </xsl:variable>

 <xsl:variable name="vMap" select=
  "document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="@foo">
  <xsl:attribute name="foo">
   <xsl:value-of select="$vMap[@key = current()]/@value"/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(因为您没有提供任何内容):

<t foo="X">
    <a foo="A">
        <b foo="B"/>
    </a>
    <c foo="C"/>
</t>

生成想要的正确结果

<t foo="8">
   <a foo="1">
      <b foo="2"/>
   </a>
   <c foo="3"/>
</t>

解释:正确使用XSLT current() 功能。


<强> II。使用密钥加速的XSLT 1.0解决方案

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

 <xsl:key name="kValFromKey" match="entry/@value" use="../@key"/>

 <xsl:variable name="vrtfMap">
  <entry key="A" value="1"/>
  <entry key="B" value="2"/>
  <entry key="C" value="3"/>
  <entry key="X" value="8"/>
 </xsl:variable>

 <xsl:variable name="vMap" select=
  "document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="@foo">
  <xsl:variable name="vCur" select="."/>

  <xsl:attribute name="foo">
   <xsl:for-each select="document('')">
    <xsl:value-of select="key('kValFromKey', $vCur)"/>
   </xsl:for-each>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于同一XML文档(上图)时,会生成相同的正确结果

<强>解释

  1. 使用<xsl:for-each select="document('')">将当前文档设置为样式表,以便key()函数将使用为此文档构建的密钥索引。

  2. 将模板中与模板匹配的节点保存在变量中,以便我们可以在xsl:for-each - current()中使用它,这里无法正确使用它,因为它获取当前节点xsl:for-each运作。

  3. 更新:OP现已在评论中澄清他最大的问题是找到最大值。

    <xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:strip-space elements="*"/>
    
         <xsl:variable name="vrtfMap">
          <entry key="A" value="1"/>
          <entry key="B" value="2"/>
          <entry key="C" value="3"/>
         </xsl:variable>
    
         <xsl:variable name="vMap" select=
          "document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
    
         <xsl:template match="/">
         <xsl:variable name="vDoc" select="."/>
    
          <xsl:variable name="vFoosMapped"
               select="$vMap[@key = $vDoc/*/*/@foo]"/>
          <max>
           <xsl:value-of select=
             "$vFoosMapped
                [not($vFoosMapped/@value > @value)]
                  /@value
             "/>
          </max>
         </xsl:template>
    </xsl:stylesheet>
    

    当给出此XML文档时(OP提供的文档缺少单个顶级元素):

    <t>
        <tag foo="A">apples</tag>
        <tag foo="C">oranges</tag>
        <tag foo="B">trees</tag>
    </t>
    

    产生了想要的正确结果

    <max>3</max>
    

    备注:在XSLT 1.0中计算最大值(或最小值 - 以类似方式)的更有效方法是:

    <xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:strip-space elements="*"/>
    
         <xsl:variable name="vrtfMap">
          <entry key="A" value="1"/>
          <entry key="B" value="2"/>
          <entry key="C" value="3"/>
         </xsl:variable>
    
         <xsl:variable name="vMap" select=
          "document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
    
         <xsl:template match="/">
         <xsl:variable name="vDoc" select="."/>
    
          <xsl:variable name="vFoosMapped"
               select="$vMap[@key = $vDoc/*/*/@foo]"/>
          <max>
           <xsl:for-each select="$vFoosMapped">
             <xsl:sort select="@value" data-type="number" order="descending"/>
    
             <xsl:if test="position() = 1">
              <xsl:value-of select="@value"/>
             </xsl:if>
           </xsl:for-each>
          </max>
         </xsl:template>
    </xsl:stylesheet>
    
      

    另一个问题,为什么我不能缩进我的代码?我正在放空间但是   它不起作用。

    这是一个他们未能修复好几个月的SO漏洞。

    很可能你正在使用IE浏览器。如果您的版本是9,请执行以下操作

    1. 按F12。

    2. 在弹出的窗口中单击最右侧的菜单,然后选择:“文档模式:IE9标准”

    3. 现在您应该能够看到带缩进的代码。