1

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

我已经阅读了一些关于如何以特殊外观实现这一点的帖子:XSLT 和 xpath v1.0 查找重复项和聚合以及文章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 中找不到 fo:table-cell 元素:表行标签。我将其理解为 FOP 无法访问第一个 xsl:for-each 循环的事实,我想知道我是否做错了什么。

如果我删除 2 个 for-each 标签,我会得到我的 pdf 但没有聚合。我在编写代码的过程中是否遗漏了什么?

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

4

2 回答 2

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>

编辑

如果你只想为每个联系人显示一行信息,那么没有必要有两个嵌套for-each或两层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>
于 2014-01-17T12:00:26.863 回答
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具有相同的@surname. 然后在每一行中,您contact使用匹配的模板处理所有元素。

<xsl:value-of select="@Smith" />

看起来错误,并且输入样本中没有该名称的属性。

于 2014-01-17T12:01:04.357 回答