Java中使用Saxon XSLT API如何正确实现数组过滤?
问题描述
输入XML
<?xml version="1.0" encoding="UTF-8"?> <Document> <tag-one> <tag-two> <tag-three> <tag-four> <tag-five> <tag-six> <tag-seven> <tag-eight> <tag-nine> <id-tag>valid_id</id-tag> </tag-nine> </tag-eight> </tag-seven> </tag-six> </tag-five> </tag-four> </tag-three> </tag-two> <tag-two> <tag-three> <tag-four> <tag-five> <tag-six> <tag-seven> <tag-eight> <tag-nine> <id-tag>invalid_id-invalid_kg</id-tag> </tag-nine> </tag-eight> </tag-seven> </tag-six> </tag-five> </tag-four> </tag-three> </tag-two> </tag-one> </Document>
当前使用的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all" version="3.0"> <xsl:param name="invalidIds"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="tag-two[contains($invalidIds, tag-three/tag-four/tag-five//*[local-name()='id-tag'])]"> </xsl:template> </xsl:transform>
Java端参数传递代码
List<String> idList = Arrays.asList("invalid_id-invalid_kg"); // 省略其余代码 // Map.of(new QName("invalidIds"), new XdmAtomicValue(idList.toString()))
问题现象
XSLT中打印invalidIds的值为[invalid_id-invalid_kg],导致两个<tag-two>都被过滤。原因是用contains做字符串匹配时,valid_id里的id子串出现在invalid_id-invalid_kg中,误触发了过滤逻辑。
解决方案
1. 修正Java端参数传递
不要把List转成字符串传递,直接传递XdmSequence类型的序列,让XSLT拿到真正的字符串集合:
List<XdmAtomicValue> xdmIds = idList.stream() .map(XdmAtomicValue::new) .collect(Collectors.toList()); XdmSequence invalidIdsParam = new XdmSequence(xdmIds); // 传递参数时使用这个XdmSequence对象 Map.of(new QName("invalidIds"), invalidIdsParam);
2. 调整XSLT的匹配逻辑
先把参数声明为字符串序列类型,再用index-of判断ID是否在无效列表中:
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all" version="3.0"> <!-- 明确参数为字符串序列类型 --> <xsl:param name="invalidIds" as="xs:string*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 用index-of判断id是否存在于无效列表,存在则过滤该tag-two --> <xsl:template match="tag-two[index-of($invalidIds, tag-three/tag-four/tag-five/tag-six/tag-seven/tag-eight/tag-nine/id-tag) ne ()]"> </xsl:template> </xsl:transform>
备选方案(字符串拼接方式,不推荐)
如果必须用字符串传递参数,可以用特殊分隔符(比如|)拼接ID列表,再在XSLT中拆分后判断:
- Java端拼接:
String invalidIdsStr = String.join("|", idList); // 传递这个拼接后的字符串 Map.of(new QName("invalidIds"), new XdmAtomicValue(invalidIdsStr));
- XSLT端处理:
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all" version="3.0"> <xsl:param name="invalidIds"/> <!-- 拆分字符串为序列 --> <xsl:variable name="invalidIdList" as="xs:string*" select="tokenize($invalidIds, '\|')"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="tag-two[index-of($invalidIdList, tag-three/tag-four/tag-five/tag-six/tag-seven/tag-eight/tag-nine/id-tag) ne ()]"> </xsl:template> </xsl:transform>
注意:这种方式要求ID中不能包含你用的分隔符,否则会拆分错误。
内容的提问来源于stack exchange,提问作者user1234SI.
相关产品推荐
相关产品推荐

