我如何使用 Saxon 以高效的方式对值执行多个 search/replace
How do I use Saxon to do multiple search/replace on values, in a way that's efficient
我使用 saxon v9 分析了一个将 XML 转换为 JSON 的 XSL 转换。探查器告诉我,转义某些字符的函数大约占总处理时间的 70%。转换很重要,否则创建的 JSON 文件将因字符中断字符串而无效。
java -jar saxon9he.jar -xsl:jsontransform.xslt -s:input.xml -o:output.json -TP
用于转义值的 "method" 如下所示:
<xsl:template name="escapejson">
<xsl:param name="string"/>
<xsl:sequence select="replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace($string, '\','\\'),
'/', '\/'),
'"', '\"'),
'
','\n'),
'
','\r'),
'	','\t'),
'\n','\n'),
'\r','\r'),
'\t','\t')"/>
</xsl:template>
我已经在 this other post 收到了 Rolf Lear @rolfl 的宝贵建议并减少了替换调用的次数:
...
replace( '\n|
','\n'),
replace( '\r|
','\r'),
replace( '\t|	','\t')
...
但不幸的是,它未能在我的时间限制内处理数据。我把xsl的原始形式和修改后的形式进行了比较,所花的时间几乎相等。
因为 XSL 在软件设备上运行,所以我没有文件级访问权限我需要一个适用于 saxon 8 的解决方案,因为这是应该在那里使用的版本。我假设将 Java 集成到 xsl 中不是一个选项,因为(但我还没有测试过)出于安全原因,设备会阻止这种情况。
您要替换的所有字符串都是单个字符,您可能可以利用这一事实。我想大多数字符串可能包含 none 这些特殊字符。因此,最好的方法可能是在进行替换之前对字符串进行初步检查,看看它是否确实包含这些字符中的任何一个。这可以使用翻译有效地完成:如果以下表达式为真
$x eq translate($x, '\/"
....', '')
那就不用更换了。运气好的话,这会将要完全处理的字符串数量减少到总数的一小部分,这样多重替换的效率就不再重要了。
另一种方法是将替换逻辑重新编码为:
string-join(
for $c in string-to-codepoints($in)
return
if ($c eq XX) then "\"
else if ($x eq XY) then "\n"
else if ....
else codepoints-to-string($c),
"")
顺便说一句,我认为 replace(X, '\n', Y)
和 replace(X, '
', Y)
的意思完全一样,所以两者都做是多余的。
您说您需要使用 Saxon 8。实际上,从 Saxon 8.0 到 Saxon 8.9 有一系列的版本,它们之间有大量的开发。我就不去查记录了,看看什么时候引入了什么功能。
我使用 saxon v9 分析了一个将 XML 转换为 JSON 的 XSL 转换。探查器告诉我,转义某些字符的函数大约占总处理时间的 70%。转换很重要,否则创建的 JSON 文件将因字符中断字符串而无效。
java -jar saxon9he.jar -xsl:jsontransform.xslt -s:input.xml -o:output.json -TP
用于转义值的 "method" 如下所示:
<xsl:template name="escapejson">
<xsl:param name="string"/>
<xsl:sequence select="replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace($string, '\','\\'),
'/', '\/'),
'"', '\"'),
'
','\n'),
'
','\r'),
'	','\t'),
'\n','\n'),
'\r','\r'),
'\t','\t')"/>
</xsl:template>
我已经在 this other post 收到了 Rolf Lear @rolfl 的宝贵建议并减少了替换调用的次数:
...
replace( '\n|
','\n'),
replace( '\r|
','\r'),
replace( '\t|	','\t')
...
但不幸的是,它未能在我的时间限制内处理数据。我把xsl的原始形式和修改后的形式进行了比较,所花的时间几乎相等。
因为 XSL 在软件设备上运行,所以我没有文件级访问权限我需要一个适用于 saxon 8 的解决方案,因为这是应该在那里使用的版本。我假设将 Java 集成到 xsl 中不是一个选项,因为(但我还没有测试过)出于安全原因,设备会阻止这种情况。
您要替换的所有字符串都是单个字符,您可能可以利用这一事实。我想大多数字符串可能包含 none 这些特殊字符。因此,最好的方法可能是在进行替换之前对字符串进行初步检查,看看它是否确实包含这些字符中的任何一个。这可以使用翻译有效地完成:如果以下表达式为真
$x eq translate($x, '\/"
....', '')
那就不用更换了。运气好的话,这会将要完全处理的字符串数量减少到总数的一小部分,这样多重替换的效率就不再重要了。
另一种方法是将替换逻辑重新编码为:
string-join(
for $c in string-to-codepoints($in)
return
if ($c eq XX) then "\"
else if ($x eq XY) then "\n"
else if ....
else codepoints-to-string($c),
"")
顺便说一句,我认为 replace(X, '\n', Y)
和 replace(X, '
', Y)
的意思完全一样,所以两者都做是多余的。
您说您需要使用 Saxon 8。实际上,从 Saxon 8.0 到 Saxon 8.9 有一系列的版本,它们之间有大量的开发。我就不去查记录了,看看什么时候引入了什么功能。