如何支持在 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
我有一个程序使用 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