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

How to support returning ArrayList in ExtensionFunction Saxon HE 9.7

我有一个程序使用 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();
}

扩展函数class:

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>   

目前,我可以调用 getEmployeeName 方法,returns 来自 xslt 的字符串。但是我如何修改 Employee class 以也支持返回 HasMap 的 ArrayList 即方法 getEmployee() 因为新的 XdmAtomicValue() 方法不将 ArrayList 作为构造函数参数。

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

您首先需要确定您想要的 XDM 类型 return:我假设这可能是 map(xs:string, xs:string)* - 这是一系列以字符串作为键和字符串作为值的映射。

您首先需要在 getResultType() 方法中将其声明为结果类型。这样做可能就足够了:

public SequenceType getResultType() {
    return SequenceType.makeSequenceType(ItemType.ANY_MAP, OccurrenceIndicator.ZERO_OR_MORE);
}

这并不像它可能的那样精确,但是提供更精确的结果类型除了导致 Saxon 对函数实际进行更仔细(和昂贵)的检查之外不会实现任何其他目的 return秒。如果您想提供更精确的 return 类型,则必须使用 ItemTypeFactory.newMapType(...).

来构造它

然后你的call()方法需要return这个类型的一个实例。

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

(a) 您可以构建一个 Java HashMap<String, String> 然后使用静态方法转换它 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 List<XdmMap>,然后使用 new XdmValue(Iterable<...> items).

将其转换为 XdmValue