XSL:计算具有相同名称的元素的值

时间:2013-03-31 17:05:34

标签: xml xslt xslt-2.0

我是XSL的新手,非常感谢处理如下结构的文件:

<UniML>
<student>
    <name>Salvatore</name>
        <m value="1">
            <i value="17.5">Balliol College</i>
            <i value="3">Kellogg College</i>
            <i value="2.88">Balliol College</i>
            <i value="32.9">Kellogg College</i>
            <i value="15.75">Balliol College</i>
        </m>
        <m value="5">
            <i value="26.25">Kellogg College</i>
            <i value="8.75">Balliol College</i>
        </m>
</student>

<student>
    <name>Karl</name>
        <m value="1">
            <i value="10.5">Balliol College</i>
            <i value="4.7">Kellogg College</i>
            <i value="2.25">Balliol College</i>
            <i value="12.6">Kellogg College</i>
        </m>
        <m value="5">
            <i value="3.75">Kellogg College</i>
            <i value="1.25">Balliol College</i>
        </m>
</student>

<student>
    <name>Serenella</name>
        <m value="1">
            <i value="4">Kellogg College</i>
            <i value="3.84">Balliol College</i>
            <i value="14.100000000000001">Kellogg College</i>
            <i value="6.75">Balliol College</i>
        </m>
        <m value="5">
            <i value="20.25">Kellogg College</i>
            <i value="42.75">Balliol College</i>
            <i value="11.25">Kellogg College</i>
            <i value="3.75">Balliol College</i>
        </m>
</student>

编辑:我想为每个学生计算每个学生的总得分m1 *(i1 + i2 + ...)+ m5 *(i1 + i2 + ...),输出是XHTML,其结构如下:

Salvatore:Balliol得分= 1 *(17.5 + 2.88 + 17.75)+ 5 *(8.8.75),Kellogg得分= 卡尔:巴利奥尔得分=,凯洛格得分=

有什么想法?

1 个答案:

答案 0 :(得分:0)

就这么简单

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

 <xsl:key name="kIByVal" match="i" use="."/>

 <xsl:template match=
  "i[not(generate-id()=generate-id(key('kIByVal',.)[1]))]"/>

 <xsl:template match="i">
  <college name="{.}" total="{sum(key('kIByVal',.)/@value)}"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

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

<student>
    <name>Salvatore</name>
    <m value="1">
    <i value="17.5">Balliol College</i>
    <i value="3">Kellogg College</i>
    <i value="2.88">Balliol College</i>
    </m>
</student>

产生了想要的正确结果:

<college name="Balliol College" total="20.38"/>
<college name="Kellogg College" total="3"/>

<强> II。如果您想保留文档的结构并只是“累计”<I> s:

<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="kIByVal" match="i" use="."/>

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

 <xsl:template match=
  "i[not(generate-id()=generate-id(key('kIByVal',.)[1]))]"/>

 <xsl:template match="i">
  <i value="{sum(key('kIByVal',.)/@value)}"><xsl:apply-templates/></i>
 </xsl:template>
</xsl:stylesheet>

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

<student>
   <name>Salvatore</name>
   <m value="1">
      <i value="20.38">Balliol College</i>
      <i value="3">Kellogg College</i>
   </m>
</student>

<强>解释

  1. 使用 Muenchian grouping method

  2. 在第二次转化中覆盖 identity rule


  3. <强>更新

    在评论中,OP增加了一项新要求:每个大学必须有每个/学生的值,每个对应的i的值必须乘以“权重” - 其父级的值{{ 1}}。

    这是一个XSLT 2.0解决方案 - 它比两遍XSLT 1.0解决方案更容易编写

    m

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

    <xsl:stylesheet version="2.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="kIByVal" match="i" use="."/>
     <xsl:key name="kStudentByCollege" match="student"
      use="m/i"/>
     <xsl:key name="kCollegePerStudentPerM" match="i"
      use="concat(generate-id(../..),'+',generate-id(..),'+',.)"/>
    
    
     <xsl:template match=
      "i[not(generate-id()=generate-id(key('kIByVal',.)[1]))]"/>
    
     <xsl:template match="i">
      <college name="{.}">
       <xsl:apply-templates mode="college" select=
        "key('kStudentByCollege', .)">
        <xsl:with-param name="pCollegeName" select="."/>
       </xsl:apply-templates>
      </college>
     </xsl:template>
    
     <xsl:template match="student" mode="college">
      <xsl:param name="pCollegeName"/>
    
      <student name="{name}">
        <xsl:sequence select=
         "sum(m/(@value*sum(key('kCollegePerStudentPerM',
                                concat(generate-id(..),'+',
                                       generate-id(.),'+',$pCollegeName)
                                )/@value
                             )
                 )
              )"/>
      </student>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    产生了想要的正确结果:

    <UniML>
        <student>
            <name>Salvatore</name>
            <m value="1">
                <i value="17.5">Balliol College</i>
                <i value="3">Kellogg College</i>
                <i value="2.88">Balliol College</i>
                <i value="32.9">Kellogg College</i>
                <i value="15.75">Balliol College</i>
            </m>
            <m value="5">
                <i value="26.25">Kellogg College</i>
                <i value="8.75">Balliol College</i>
            </m>
        </student>
        <student>
            <name>Karl</name>
            <m value="1">
                <i value="10.5">Balliol College</i>
                <i value="4.7">Kellogg College</i>
                <i value="2.25">Balliol College</i>
                <i value="12.6">Kellogg College</i>
            </m>
            <m value="5">
                <i value="3.75">Kellogg College</i>
                <i value="1.25">Balliol College</i>
            </m>
        </student>
        <student>
            <name>Serenella</name>
            <m value="1">
                <i value="4">Kellogg College</i>
                <i value="3.84">Balliol College</i>
                <i value="14.100000000000001">Kellogg College</i>
                <i value="6.75">Balliol College</i>
            </m>
            <m value="5">
                <i value="20.25">Kellogg College</i>
                <i value="42.75">Balliol College</i>
                <i value="11.25">Kellogg College</i>
                <i value="3.75">Balliol College</i>
            </m>
        </student>
    </UniML>