开发者

XSLT Problem Using Muenchian Method of Grouping

I'm having a very odd problem with grouping a set of nodes in a document and getting a unique list based on a set of contained values.

Given the following 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>

I am trying to generate a pipe-delimited string with all of the names in the "Friend" tags. Here is the current stylesheet I'm using:

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

The problem I'm having is that the output omits the last friend. Here is the result:

Billy Bob Smith|

Funny thing is that if I remove the last "Gift" element, it produces the output I'm looking for:

Billy Bob Smith|Mary Jo Smith

For reference, here is the Java code used to execute the transform:

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();
    }
  }
}

Any assistance you can offer would be welcome.


Your transform tested with Saxon 6.5 is working perfectly and it produces the wanted result:

Billy Bob Smith|Mary Jo Smith

It might be an issue related to the java XSLT api. May be the API does not fully support XSLT 1.0 features like, for instance, xsl:key. You can make a further test and try not using keys at all.

For example, this template performs the same task without using any 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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜