我有大约10个要在XML文档上应用的参数(键-值对)列表。
每当找到TESTWORD
作为值时,请使用以下键并将其替换为适当的值。还要替换该节点的名称。
输入:
<Company>
<Employee>
<FirstName>Homer</FirstName>
<LastName>Simpson</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Springfield</City>
<Note>TESTWORD key1</Note> <!-- change this -->
</Address>
</Employee>
<Employee>
<FirstName>Peter</FirstName>
<LastName>Griffin</LastName>
<ContactNo>0987654321</ContactNo>
<Address>
<City>Quahog</City>
<Note>TESTWORD key2</Note> <!-- change this -->
</Address>
</Employee>
</Company>
预期输出:
<Company>
<Employee>
<FirstName>Homer</FirstName>
<LastName>Simpson</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Springfield</City>
<NewElem>My new value</NewElem> <!-- changed -->
</Address>
</Employee>
<Employee>
<FirstName>Peter</FirstName>
<LastName>Griffin</LastName>
<ContactNo>0987654321</ContactNo>
<Address>
<City>Quahog</City>
<NewElem>Another value</NewElem> <!-- changed -->
</Address>
</Employee>
</Company>
我的XSLT方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes" method="xml" encoding="utf-8" />
<!-- Param list -->
<xsl:param name="key1" select="'My new value'" />
<xsl:param name="key2" select="'Another value'" />
<!-- ... more params -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Note[.='TESTWORD key1']"> <!-- iterate all params -->
<xsl:element name="NewElem">
<xsl:value-of select="$key1" /> <!-- replace all values -->
</xsl:element>
</xsl:template>
</xsl:stylesheet>
第一次出现的<Note>TESTWORD key1</Note>
被正确地替换为<NewElem>My new value</NewElem>
。但其余事件没有。
我可以复制这部作品的x倍:
<xsl:template match="Note[.='TESTWORD keyX']">
<xsl:element name="NewElem">
<xsl:value-of select="$keyX" />
</xsl:element>
</xsl:template>
但是也许有一种迭代方法?
PS:我正在使用 Java 。
答案 0 :(得分:1)
在Saxon 9.8和更高版本中,您可以声明XSLT 3 / XPath 3.1类型为map(xs:string, xs:string)
的参数(即具有字符串键和值的映射)来表示键/值对。然后,您可以处理它们并以匹配模式使用它们:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="map"
as="map(xs:string, xs:string)"
select="map {
'key1' : 'My new value',
'key2' : 'Another value'
}"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:variable name="map-keys" select="map:keys($map)"/>
<xsl:template match="Note[some $key in $map-keys satisfies . = 'TESTWORD ' || $key]">
<NewElemen>
<xsl:value-of select="$map($map-keys[current() = 'TESTWORD ' || .])"/>
</NewElemen>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pNmCzsU
从Java中,有一些方法可以从类似的Java集合中构造这样的XdmMap,例如makeMap
(http://saxonica.com/html/documentation9.9/javadoc/net/sf/saxon/s9api/XdmMap.html#makeMap-java.util.Map-)将java.util.Map转换为XdmMap。
建议将s9api和Xslt30Transformer与Saxon 9.8或更高版本一起使用以运行XSLT 3,然后可以在带有http://saxonica.com/html/documentation9.9/javadoc/net/sf/saxon/s9api/Xslt30Transformer.html#setStylesheetParameters-java.util.Map-的类实例上设置参数。
但是,如果Saxon在类路径上,您还可以使用JAXP XdmMap
来传递Transformer
:
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource("map-test1.xsl"));
Map<String, String> map1 = new HashMap<>();
map1.put("key2", "value passed in from JAXP API");
transformer.setParameter("map", XdmMap.makeMap(map1));
transformer.transform(new StreamSource("input-sample1.xml"), new StreamResult(System.out));