2009-06-02 92 views
1

如果这是一个非常简单的问题,请道歉;我不使用XSLT,并且在网络上找不到太多建议,因为搜索结果有很多污染!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中有各种分组选项,但不幸的是,xsltproc似乎并不支持这一点。任何帮助将受到感谢。

非常感谢,

雅各

回答

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> 
+0

谢谢;这很有帮助。我无法解决怎么做,虽然是“无论你需要什么”一点。通过“内容”对XML进行分组是否有一种简单的方法来计算特定“内容”值在xml中出现的次数? – 2009-06-02 11:43:19

+0

对不起,请参阅更新 – annakata 2009-06-02 12:18:51

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> 
+0

啊,对不起,应该更清楚地说明一下自己。这将产生结果“铅笔”,因为有17支铅笔。我想要的是制作“铅笔”,因为“铅笔”出现两次,“笔”和“尺子”出现一次。 – 2009-06-02 11:36:37

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> 

注意重复的条目每次计数,$理货将包含:

<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处理器,您可能需要将$使用节点集函数对一个节点集进行计数。

相关问题