Java 如何在ExtensionFunction Saxon HE 9.7中支持返回ArrayList

Java 如何在ExtensionFunction Saxon HE 9.7中支持返回ArrayList,java,xslt,saxon,Java,Xslt,Saxon,我有一个使用Saxon HE 9.7进行XML转换的程序 public String transform() throws TransformerException { TransformerFactory factory = TransformerFactory.newInstance(); TransformerFactoryImpl tFactoryImpl = (TransformerFactoryImpl) factory; Configuration sax

我有一个使用Saxon HE 9.7进行XML转换的程序

public String transform() throws TransformerException {
    TransformerFactory factory = TransformerFactory.newInstance();
    TransformerFactoryImpl tFactoryImpl = (TransformerFactoryImpl) factory;

    Configuration saxonConfig = tFactoryImpl.getConfiguration();
    Processor processor = (Processor) saxonConfig.getProcessor();

    processor.registerExtensionFunction(new Employee());

    Source xslt = new StreamSource(new File("mappings.xslt"));
    Transformer transformer = factory.newTransformer(xslt);

    Source text = new StreamSource(new File("payload.xml"));
    transformer.transform(text, new StreamResult(sw));
    return sw.toString();
}
ExtensionFunction类:

public class Employee implements ExtensionFunction {

private List<HashMap<String, String>> employee = new ArrayList<HashMap<String, String>>();
private String employeeName = "John";

public List<HashMap<String, String>> getEmployee() {
    HashMap<String, String> map1 = new HashMap<>();
    map1.put("name", "john");
    HashMap<String, String> map2 = new HashMap<>();
    map2.put("age", "30");
    employee.add(map1);
    employee.add(map2);
    return employee;
}

public String getEmployeeName(){
    return employeeName;
}

@Override
public XdmValue call(XdmValue[] arg0) throws SaxonApiException {
    return new XdmAtomicValue(getEmployeeName());
}

@Override
public SequenceType[] getArgumentTypes() {
    return new SequenceType[] {};
}

@Override
public QName getName() {
    return new QName("test.extension.Employee", "getEmployeeName");
}

@Override
public SequenceType getResultType() {
    return SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE);
}
XSLT文件:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0" xmlns:Employee="test.extension.Employee" 
xmlns:saxon="http://saxon.sf.net/">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="list" 
select="Employee.getEmployee()" />
<xsl:variable name="count" select="count($list)" />
<xsl:template match="/">
    <company>
            <employee>
                <xsl:attribute name="name">
                    <xsl:value-of select="$list[1]" />
                </xsl:attribute>
            </employee>
    </company>
</xsl:template>
</xsl:stylesheet>   

目前,我能够调用从xslt返回字符串的getEmployeeName方法。但是我如何修改Employee类以同时支持返回HasMap的ArrayList,即作为新XdmAtomicValue方法的方法getEmployee不将ArrayList作为构造函数参数。

我将回答Saxon 9.9,因为这是您真正应该使用的版本。在Saxon 9.7中不存在XdmMap类,因此在该版本中传递Java和XSLT之间的映射将是困难或不可能的

首先需要确定要返回的XDM类型:我假设这可能是mapxs:string,xs:string*——这是一个映射序列,其中字符串作为键,字符串作为值

首先需要在getResultType方法中将其声明为结果类型。这可能足以做到:

public SequenceType getResultType() {
    return SequenceType.makeSequenceType(ItemType.ANY_MAP, OccurrenceIndicator.ZERO_OR_MORE);
}
这可能不够精确,但提供更精确的结果类型除了让Saxon对函数实际返回的内容进行更仔细、更昂贵的检查之外,别无其他用处。如果您想提供更精确的返回类型,则必须使用ItemTypeFactory.newMapType….来构造它

然后调用方法需要返回此类型的实例

您需要将每个员工表示为一个XdmMap。有两种方法可以构造XdmMap

a您可以构建Java HashMap,然后使用静态方法XdmMap.makeMap对其进行转换

b您可以逐步构建地图:

XdmMap map = new XdmMap();
map = map.put(new XdmAtomicValue("name"), new XdmAtomicValue("John Doe"));
map = map.put(new XdmAtomicValue("age"), new XdmAtomicValue("24"));
请注意,XdmMap是不可变的,因此每个put操作都会创建一个新的XdmMap实例;原稿不变


最后,您需要构造这些XdmMap实例的序列。最简单的方法是构造一个包含所有映射的Java列表,然后使用新的XDMValueLiterable项将其转换为XdmValue。

非常感谢。我使用了Saxon HE 9.9,并且能够将结果转换为XdmValue。但是,我想让getEmployeeName和getEmployee方法都可以访问。我需要为每个函数创建单独的类,还是可以将它们都放在一个类中?它们应该是单独的类-每个函数一个类。当使用列表项的值时,我遇到此错误:FOTY0013:无法原子化映射{name:john},映射{age:30}。我已经用xslt文件更新了这个问题。在xsl:variable中声明类型总是一个好主意:在本例中为=mapxs:string,xs:string,还是mapxs:string,xs:string*——一个映射序列?无论如何,将xsl:value应用于映射都是行不通的。您需要从映射中提取特定值,例如$list[1]?名称。