使用Muenchian分组方法的XSLT问题

时间:2011-06-15 20:04:50

标签: java xslt muenchian-grouping

我在文档中对一组节点进行分组并根据一组包含的值获取唯一列表时遇到了一个非常奇怪的问题。

给出以下XML:

<Person>
    <FirstName>John</FirstName>
    <MiddleName>Q</MiddleName>
    <LastName>Person</LastName>
    <Gift>
      <Thing>Moon</Thing>
      <Friend>
          <FirstName>Billy</FirstName>
          <MiddleName>Bob</MiddleName>
          <LastName>Smith</LastName>
      </Friend>
      <Friend>
          <FirstName>Mary</FirstName>
          <MiddleName>Jo</MiddleName>
          <LastName>Smith</LastName>
      </Friend>
    </Gift>
    <Gift>
      <Thing>Pencil</Thing>
    </Gift>
</Person>

我正在尝试生成一个管道分隔的字符串,其中包含“Friend”标记中的所有名称。这是我正在使用的当前样式表:

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

  <xsl:key name="Friends" match="Friend" use="concat(FirstName, MiddleName, LastName)"/>

  <xsl:template match="/Person">
    <xsl:for-each select="Gift/Friend[count(. | key('Friends', concat(FirstName, MiddleName, LastName))[1]) = 1]">
      <xsl:apply-templates select="."/>
      <xsl:if test="position()!=last()">
        <xsl:text>|</xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Friend">
    <xsl:variable name="name">
      <xsl:value-of select="FirstName"/><xsl:text> </xsl:text>
      <xsl:value-of select="MiddleName"/><xsl:text> </xsl:text>
      <xsl:value-of select="LastName"/><xsl:text> </xsl:text>
    </xsl:variable>
    <xsl:value-of select="normalize-space($name)"/>
  </xsl:template>

</xsl:stylesheet>

我遇到的问题是输出省略了最后一位朋友。结果如下:

Billy Bob Smith|

有趣的是,如果我删除最后一个“Gift”元素,它会产生我正在寻找的输出:

Billy Bob Smith|Mary Jo Smith

供参考,以下是用于执行转换的Java代码:

package testing;

import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class test
{
  public static void main( String[] args )
  {
    try
    {     
      StreamSource xsl = new StreamSource( "xslt/person.xslt" );
      StreamSource xml = new StreamSource( "xslt/person.xml" );
      Transformer txfm = TransformerFactory.newInstance().newTransformer(xsl);
      if ( txfm != null )
      {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        txfm.transform( xml, new StreamResult(bytes) );
        System.out.println( bytes.toString() );
      }      

    }
    catch ( Exception e )
    {
      e.printStackTrace();
    }
  }
}

欢迎您提供任何帮助。

1 个答案:

答案 0 :(得分:0)

您使用 Saxon 6.5 测试的转换效果非常好,可以产生想要的结果:

Billy Bob Smith|Mary Jo Smith

这可能是与java XSLT api相关的问题。可能是API不完全支持XSLT 1.0等功能,例如xsl:key。您可以进行进一步测试,并尝试不使用密钥。

例如,此模板在不使用任何键的情况下执行相同的任务:

    <xsl:template match="/Person">
        <xsl:for-each select="Gift/Friend[not(
            concat(FirstName,MiddleName,LastName)
            =
            preceding::Friend[concat(FirstName, MiddleName, LastName)]
            )]">
      <xsl:apply-templates select="."/>
      <xsl:if test="position()!=last()">
        <xsl:text>|</xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>