【问题标题】:XSLT sum by lookup value from another fileXSLT 通过从另一个文件中查找值求和
【发布时间】:2011-05-20 11:48:03
【问题描述】:

我想从以下 2 个 XML 文件中获取特定学生的总数:

--- 文件:mark.xml ----

<marks>
  <mark type="HD">10</mark>
  <mark type="D">8</mark>
  <mark type="C">5</mark>
</marks>

--- 文件:studentRecord.xml ---

<students>
  <student id="1234">
    <grade>HD</grade>
  </student>
  <student id="1234">
    <grade>C</grade>
  </student>
  <student id="1111">
    <grade>D</grade>
  </student>
</students>

我怎样才能得到拥有id 1234的学生的总分?应该是 15。

【问题讨论】:

  • 您使用的是什么编程环境/技术?
  • XSLT 是否进行多文件查询?我认为您需要 XQuery(或一些主机环境)。先将两份文件合二为一可行吗?
  • 好问题。 +1。请参阅我的答案,了解一个完整、简短且简单的 XSLT 解决方案,它实际上是一个单行 XPath 表达式。
  • 我的回答对您有用吗?考虑接受最佳答案?

标签: xslt sum lookup


【解决方案1】:

这是一个简短的 XSLT 解决方案(实际上它只是 XPath):

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

 <my:MarkValues>
        <marks>
            <mark type="HD">10</mark>
            <mark type="D">8</mark>
            <mark type="C">5</mark>
        </marks>
 </my:MarkValues>

 <xsl:template match="/*">
     <xsl:value-of select=
     "sum(document('')/*
           /my:MarkValues/*/*
               [@type = current()/*
                          [@id='1234']/grade
             ]
        )"/>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的 XML 文档时(名为“studentRecord.xml”):

<students>
    <student id="1234">
        <grade>HD</grade>
    </student>
    <student id="1234">
        <grade>C</grade>
    </student>
    <student id="1111">
        <grade>D</grade>
    </student>
</students>

产生了想要的答案

15

如果您想将标记值保存在单独的文件中(不像上面那样嵌入到 XSLT 样式表中),XPath 表达式应该稍微改变(只是document() 函数的参数:

sum(document('mark.xml')/*/*
                     [@type = current()/*
                                     [@id='1234']/grade
                     ]
   )

解释

  1. 使用 XSLT document() 函数。

  2. 使用 XSLT current() 函数。

  3. 使用 XPath sum() 函数。

【讨论】:

  • 感谢这个 XPath 技巧。如果可能的话,我正在徘徊。这就是为什么我的回答略有不同(并且可能很愚蠢)。如果您有时间和乐趣,我想知道您对另一个question 的意见(或回答)。再次感谢您分享您的知识。
  • @empo:不客气。我希望你不会讨厌我的 cmets 对你的解决方案...... :)
【解决方案2】:

在下面的转换中,我首先使用收集的值构建一个变量,然后使用 XPath sum() 函数来获取结果。它不像@Dimitre 方法那样优雅和聪明,但我还是想发布:)


XSLT 2.0Saxon-HE 9.2.1.1J

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

    <xsl:variable name="lookup" select="document('lookup.xml')/marks"/> 

    <xsl:template match="students">

        <xsl:variable name="values">
            <values>
                <xsl:for-each select="student[@id='1234']">
                    <value><xsl:value-of select="$lookup/mark[@type=current()/grade]"/></value>
                </xsl:for-each>
            </values>
        </xsl:variable>

        <xsl:value-of select="sum($values//value)"/>

    </xsl:template>

</xsl:stylesheet>

应用于问题中提供的输入数据的结果只是总和:

 15

【讨论】:

  • 这不是一个“XSLT 1.0”解决方案——永远不要根据假设 XSLT 1.0 转换在 XSLT 2.0 处理器上成功运行的事实做出任何结论。尝试使用 Saxon 6.5.x、MSXMLx、.NET XslCompiledTransform 或任何其他符合 XSLT 1.0 的 XSLT 处理器。然后改正你的错误,或者更好,想一个更好的解决方案。请注意:我不会对你投反对票。我相信我们参与 SO 是一种学习体验,很高兴看到每个人都成长。
  • @Dimitre:我认为 Saxon 能够根据其中指定的版本处理 xsl。我现在看到了关于 1.0 版警告的原因。我已经尝试过使用 Saxon 6 的解决方案,但它失败了。如果我没记错的话,在 XSLT 1.0 中我不能在这样的节点集上使用 xsl:value-of。谢谢你的评论。
【解决方案3】:

试试这个 C# 代码:

 var studenst = XElement.Load("studentRecord.xml");
 var marks= XElement.Load("marks.xml");

 Dictionary<string, int> marksDic = new Dictionary<string, int>();
 foreach (XElement m in marks.Descendants())
      {
           if (m.Attribute("type") != null)
                marksDic.Add(m.Attribute("type").Value, int.Parse(m.Value));
      }


      foreach (XElement s in studenst.Descendants().Where(x=>(x.Attribute("id") !=null ?int.Parse(x.Attribute("id").Value):0)==id))
      {

           Console.WriteLine(marksDic.Where(x => x.Key == s.Value)
                .Select(x => x.Value).Single());
      }
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 2015-01-14
    • 2017-11-27
    • 1970-01-01
    相关资源
    最近更新 更多