道歉,如果这是一个非常简单的问题;我不太习惯使用XSLT而且我在网上找不到太多建议,因为搜索结果中有很多污染!
我有一个以下形式的XML文档。它的主要目的是通过XSLT以几种方式重新格式化,以便以几种不同的格式显示。
<desk>
<drawer>
<contents>pencils</contents>
<quantity>2</quantity>
</drawer>
<drawer>
<contents>pens</contents>
<quantity>15</quantity>
</drawer>
<drawer>
<contents>pencils</contents>
<quantity>3</quantity>
</drawer>
<drawer>
<contents>rulers</contents>
<quantity>2</quantity>
</drawer>
</desk>
我想从xml中提取两条信息:i)平均数量; ii)xml中出现次数最常遇到的内容(即“铅笔”,因为它出现两次而不是“笔”,因为它具有最大的数量)。这个想法是,这可以通过管道传输到一个非常简单的shell脚本中。因此,我认为获取此信息的最简单方法是编写几个简短的xsl样式表,然后使用xsltproc获取数据。
第一条信息似乎很简单。样式表的核心就是这一行:
<xsl:value-of select="(sum(drawer/quantity)) div (count(drawer))" />
但是我被第二次卡住了。
我想我可以使用这样的东西循环浏览每个单独内容的列表:
<xsl:for-each select="drawer[not(contents = preceding-sibling::drawer/contents)]" />
但我不太确定如何计算具有$ current_contents的元素数量及其内容元素的值。我也无法看到按结果排序的简单方法,因此我可以获得最常遇到的内容值的名称。
我觉得在XSLT 2.0中使用各种group-by选项会更容易,但不幸的是,xsltproc似乎并不支持它。我们将非常感激地提供任何帮助。
非常感谢,
雅各
答案 0 :(得分:2)
正如在XSLT中解决了很多问题一样,我认为你的答案是muenchian grouping。根据您感兴趣的任何数据进行分组,对于每个对象,可以使用xsl:sort,然后对第一个结果执行任何操作。
未经测试,头脑发热,可能更清洁的代码:
<xsl:key name="average" match="desk/drawer/contents" use="text()"/>
<xsl:template match="/">
<xsl:for-each select="desk/drawer/contents[generate-id() = generate-id(key('average',text())[1])]">
<xsl:sort select="count(//desk/drawer/contents[text()=current()])" order="descending"/>
<xsl:if test="position()=1">
Most common value: "<xsl:value-of select="current()"/>" (<xsl:value-of select="count(//desk/drawer/contents[text()=current()])"/>)
</xsl:if>
</xsl:for-each>
</xsl:template>
答案 1 :(得分:0)
for-each
中的排序是通过sort
元素完成的。只需按数量排序(如果您只想要最频繁的话),添加<xsl:if test="position()=1">
标记只能获得循环中的第一个。
<xsl:for-each select="drawer">
<xsl:sort select="quantity" data-type="number" order="descending"/>
<xsl:if test="position()=1">
Most frequent: <xsl:value-of select="contents"> with <xsl:value-of select="quantity"> items
</xsl:if>
</xsl:for-each>
答案 2 :(得分:0)
已经有一段时间了,但我认为这些方面的内容可能有用。
首先统计所有内容
<xsl:variable name="tally">
<xsl:for-each select="drawer">
<contents count="{count(drawer[contents = current()/contents])}"><xsl:value-of select="contents"/></contents>
</xsl:for-each>
</xsl:variable>
请注意,每次都会计算重复的条目,$ tally将包含:
<contents count="2">pencils</contents>
<contents count="1">pens</contents>
<contents count="2">pencils</contents>
<contents count="1">rulers</contents>
然后使用它来查找没有其他具有更高计数的那个:
<xsl:variable name="mostfrequentcontents" select="$tally/contents[not($tally/contents/@count > @count)]" />
根据您的xslt处理器,您可能必须使用节点集函数将$ tally转换为节点集。