XSLT v1.0 - Muenchian分组问题

时间:2014-01-17 11:52:43

标签: xml xslt xpath apache-fop muenchian-grouping

在尝试使用XSL-FO,XSLT和Apache FOP生成格式化的pdf时尝试聚合xml重复项时遇到问题。

我已经阅读了一些关于如何实现这一点的帖子,特别注意发布:XSLT and xpath v1.0 find duplicates and aggregate以及文章Muenchian Grouping,但我仍然遇到问题。

我的XML如下:

<Document>
    <RecordDetails>
        <Record>
            <contact id="0001" title="Mr" forename="John" surname="Smith" />
        </Record>
        <Record>
            <contact id="0002" title="Dr" forename= "Amy" surname="Jones" />
        </Record>
        <Record>    
            <contact id="0003" title="Mr" forename="Jack" surname="Smith" />
        </Record>
    </RecordDetails>
</Document>


我想要实现的是在我的pdf格式输出上聚合所有与srname属性具有相同值的联系人项目。我当前的XSL代码如下:

<xsl:key name="contactsbysurname" match="contact" use="@surname"/> 


<xsl:template match="Record">
      *<xsl:for-each select="contact[generate-id(.)=generate-id(key('contactsbysurname',@surname)[1])]">
          <xsl:for-each select="key('contactsbysurname',@surname)"> *
            <fo:table-row font-size="6.5pt">                              
                  <xsl:apply-templates select="contact"/>
            </fo:table-row>     
          </xsl:for-each>
      </xsl:for-each>
</xsl:template>    


<xsl:template match="contact">
    <fo:table-cell>
        <fo:block text-align="center">
            <xsl:value-of select="@title" />
        </fo:block>
    </fo:table-cell>
    <fo:table-cell>
        <fo:block text-align="center">
            <xsl:value-of select="@Smith" />
        </fo:block>
    </fo:table-cell>
    <fo:table-cell>
        <fo:block text-align="center">
            ...
        </fo:block>
    </fo:table-cell>
</xsl:template> 

似乎在模板Record中,当我尝试包含2个xsl:for-each循环以实现Muenchian方法时,FOP返回一个错误,其中涉及到没有fo:table-cell元素可以在里面找到fo:table-row标签。我理解这是因为FOP无法访问第一个xsl:for-each循环,我想知道我是否做错了。

如果我删除2 for-each标签,我会得到我的pdf但没有聚合。我在编写代码的方式上遗漏了什么吗?

非常感谢所有帮助! 谢谢。

2 个答案:

答案 0 :(得分:1)

如果您只是更改此行,它应该可以正常工作:

<xsl:apply-templates select="contact"/>

到此:

<xsl:apply-templates select="."/>

但是,我建议更像这样构建你的XSLT:

  <xsl:template match="Record">
    <xsl:apply-templates
      select="contact[generate-id() = 
                        generate-id(key('contactsbysurname',@surname)[1])]"
      mode="group" />
  </xsl:template>

  <xsl:template match="contact" mode="group">
    <xsl:apply-templates select="key('contactsbysurname',@surname)" />
  </xsl:template>

  <xsl:template match="contact">
    <fo:table-row font-size="6.5pt">
      <fo:table-cell>
        <fo:block text-align="center">
          <xsl:value-of select="@title" />
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block text-align="center">
          <xsl:value-of select="@surname" />
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block text-align="center">
          ...
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>

修改

如果您只想为每个联系人显示一行信息,则无需拥有两个nestes for-each es或两层contact模板。在这种情况下,它甚至更简单:

  <xsl:template match="Record">
    <xsl:apply-templates
      select="contact[generate-id() = 
                        generate-id(key('contactsbysurname',@surname)[1])]" />
  </xsl:template>

  <xsl:template match="contact">
    <fo:table-row font-size="6.5pt">
      <fo:table-cell>
        <fo:block text-align="center">
          <xsl:value-of select="@title" />
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block text-align="center">
          <xsl:value-of select="@surname" />
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block text-align="center">
          ...
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>

答案 1 :(得分:0)

更改

<xsl:template match="Record">
      *<xsl:for-each select="contact[generate-id(.)=generate-id(key('contactsbysurname',@surname)[1])]">
          <xsl:for-each select="key('contactsbysurname',@surname)"> *
            <fo:table-row font-size="6.5pt">                              
                  <xsl:apply-templates select="contact"/>
            </fo:table-row>     
          </xsl:for-each>
      </xsl:for-each>
</xsl:template>  

<xsl:template match="RecordDetails">
      <xsl:for-each select="Record/contact[generate-id(.)=generate-id(key('contactsbysurname',@surname)[1])]">
            <fo:table-row font-size="6.5pt">                              
                  <xsl:apply-templates select="key('contactsbysurname',@surname)"/>
            </fo:table-row>     
          </xsl:for-each>
      </xsl:for-each>
</xsl:template>  

对于contact的每个@surnamecontact,这应该为您提供一行。然后在每一行中使用匹配的模板处理所有<xsl:value-of select="@Smith" /> 元素。

{{1}}

看起来不对,输入样本中没有该名称的属性。