关于xml:Saxon无法找到函数:current-group

Saxon cannot find function: current-group

我正在尝试将Saxon与XSLT样式表一起使用,并使用XSLT2规范(http://www.w3.org/TR/xslt20/#xsl-for-each-group)中的代码示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<table xsl:version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <tr>
    <th>Position</th>
    <th>Country</th>
    <th>City List</th>
    <th>Population</th>
  </tr>
  <xsl:for-each-group select="cities/city" group-by="@country">
    <tr>
      <td><xsl:value-of select="position()"/></td>
      <td><xsl:value-of select="@country"/></td>
      <td>
        <xsl:value-of select="current-group()/@name" separator=","/>
      </td>
      <td><xsl:value-of select="sum(current-group()/@pop)"/></td>
    </tr>
  </xsl:for-each-group>
</table>

我在pom.xml中使用以下内容

1
2
3
4
5
<dependency>
  <groupId>net.sf.saxon</groupId>
  Saxon-HE</artifactId>
  <version>9.6.0-3</version>
</dependency>

和运行它的代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    @Test
    public void testSaxonXslt2GroupTest1() throws Exception {

        File xml_file = Fixtures.XSLT2_TEST1_XML;
        File xsl_file = Fixtures.XSLT2_TEST1_XSL;


        TransformerFactory tfactory = net.sf.saxon.TransformerFactoryImpl.newInstance();
        Transformer transformer = tfactory.newTransformer(new StreamSource(xsl_file));
        File saxonDir = new File("target/saxon/");
        saxonDir.mkdirs();
        try {
            transformer.transform(new StreamSource(xml_file),  
                new StreamResult(new FileOutputStream(new File(saxonDir,"test1.xml"))));
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

这会在输出控制台上引发错误

1
2
3
SystemId Unknown; Line #13; Column #70; Could not find function: current-group
SystemId Unknown; Line #13; Column #70; function token not found.
(Location of error unknown)java.lang.NullPointerException

我正在使用的Saxon版本中是否缺少此功能,或者我做错了什么?


JAXP再次罢工!问题是,您实际上没有在运行Saxon。

执行此操作时:

1
factory = net.sf.saxon.TransformerFactoryImpl.newInstance();

它看起来好像您正在调用Saxon方法,不是吗?但是在Java中,不能以这种方式覆盖静态方法(如果可以的话,我会...)。您只需在基类上调用newInstance()方法,该方法将在类路径中搜索它发现的第一个XSLT处理器。如果要显式调用Saxon,最好通过执行

避免类路径搜索

1
factory = new net.sf.saxon.TransformerFactoryImpl();


我现在发现了一些可行的方法。

1
2
3
4
5
6
7
    @Test
    public void testSaxonXslt2GroupTest1() throws Exception {
//      http://stackoverflow.com/questions/9925483/calling-java-from-xsl-saxon  

        File xml_file = Fixtures.XSLT2_TEST1_XML;
        File xsl_file = Fixtures.XSLT2_TEST1_XSL;
        LOG.debug(FileUtils.readFileToString(xsl_file));

///用属性方法替换完全限定的类名,似乎可行。

1
2
3
        System.setProperty("javax.xml.transform.TransformerFactory",
               "net.sf.saxon.TransformerFactoryImpl");
        TransformerFactory tfactory = TransformerFactory.newInstance();

//

1
2
3
4
5
6
7
8
9
10
  Transformer transformer = tfactory.newTransformer(new StreamSource(xsl_file));
            File saxonDir = new File("target/saxon/");
            saxonDir.mkdirs();
            try {
                transformer.transform(new StreamSource(xml_file),  
                    new StreamResult(new FileOutputStream(new File(saxonDir,"test1.xml"))));
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }

我曾经认为使用精确的构造函数就足够了,但似乎还不够。