首页 > 解决方案 > 迭代 XSLT(Saxon) 中 Java 扩展函数返回的 ArrayList

问题描述

我有一个使用 XSLT 执行 XML 映射的程序。我为此使用 Saxon-HE-9.7 库。我还在 XSLT 中使用自反扩展函数。

XSLT 调用一个 java 函数,该函数返回ArrayList<HashMap<String, String>>

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0" xmlns:SQLService="com.db.SQLService"  xmlns:ArrayList="java:java.util.ArrayList" xmlns:HashMap="java.util.HashMap" >
<xsl:output method="xml" indent="yes" />
<xsl:variable name="city">Texas</xsl:variable>
<xsl:variable name="query" select="'Select name, emp_id from employee where city = ?'" />
<xsl:variable name="list" select="SQLService:executeQueryMultiResult($query, $city)" />
<xsl:template match="/">
    <test>
        <xsl:for-each select="abc/company[@type='product']">
            <employee>
                <xsl:attribute name="details">
                    <xsl:value-of select="$list" />
                </xsl:attribute>
            </employee>
        </xsl:for-each>
    </test>
</xsl:template>
</xsl:stylesheet>   

我只得到列表中的单条记录,这是executeQueryMultiResult 返回的列表的最后一条记录。

我想存储和迭代列表的所有元素?

标签: javaxsltsaxon

解决方案


首先,我有点惊讶的是,当您迭代 时abc/company[@type='product'],的主体xsl:for-each不会以任何方式依赖于当前 selected company。这意味着此循环的每次迭代都将产生完全相同的输出。

在默认的 Java-to-XPath 转换下,ArrayList应该转换为 XPath 序列,但 java Maps 不会转换为 XPath maps;它们需要作为外部对象访问。

查看count($list)返回的内容并检查它是否符合您的期望。

之后

我无法重现该问题。我是这样测试的:

public void testListOfMaps() {
        try {
            Processor p = new Processor(true);

            XsltCompiler c = p.newXsltCompiler();
            String s = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                    "<xsl:stylesheet version=\"3.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n" +
                    "    xmlns:jf=\"java:s9apitest.TestReflexionHelper\">\n" +
                    "    <xsl:output method=\"text\" />\n" +
                    "    <xsl:template name='main'>\n" +
                    "        <xsl:variable name=\"theList\" select=\"jf:getListOfMaps('Weds', 'Wednesday')\" />\n" +
                    "        <xsl:value-of select=\"count($theList)\" />\n" +
                    "        <xsl:value-of select=\"Q{java:java.util.Map}get($theList[1], 'Weds')\" />\n" +
                    "    </xsl:template>\n" +
                    "</xsl:stylesheet>";
            XsltTransformer t = c.compile(new StreamSource(new StringReader(s))).load();
            StringWriter out = new StringWriter();
            Serializer ser = p.newSerializer(out);
            t.setDestination(ser);
            t.setInitialTemplate(new QName("main"));
            t.transform();
            assertTrue(out.toString().equals("2Wednesday"));
        } catch (SaxonApiException e1) {
            fail(e1.getMessage());
        }
    }

其中扩展函数 jf:getListOfMaps() 是:

public static List<Map<String, String>> getListOfMaps(String x, String y) {
        Map<String, String> m = new HashMap<>();
        m.put("Mon", "Monday");
        m.put("Tues", "Tuesday");
        m.put(x, y);
        Map<String, String> n = new HashMap<>();
        m.put("Jan", "January");
        m.put("Feb", "February");
        List<Map<String, String>> list = new ArrayList<>();
        list.add(m);
        list.add(n);
        return list;
    }

测试表明 Saxon 的行为符合规范:Java 映射列表被转换为外部对象的 XPath 序列,其中外部对象是 Java 映射的包装器,允许使用底层 Java 方法。

我在 Saxon 9.9 上运行了这个(不再支持 9.7)。

我建议您尝试生成一个简化问题的重现,方法是用任何人都可以运行以进行测试的相同签名的虚拟存根替换您的扩展函数。

我还建议您确切地告诉我们您的环境是什么。您说您使用的是 Saxon-HE,我有点不解,因为 Saxon-HE 不支持反身扩展功能。


推荐阅读