我有一个关于eXist-db 4.5输出转义的问题:
我正在使用transform:transform
(使用$serialization-options
= method=text media-type=application/text
)和xmldb:store
(使用$mime-type
= text/plain
)将XSL Transformation的输出保存回数据库。在我正在使用的xslt-Stylesheet中
<xsl:value-of select="concat('Tom ', '&', ' Peter')"/>
但是保存回eXist的输出看起来像Tom $amp; Peter
而不是Tom & Peter
,就像我期待的那样。当我指定disable-output-escaping="yes"
时eXist以错误终止...
<xsl:value-of select="concat('Tom ', '&', ' Peter')" disable-output-escaping="yes"/>
像transform:stream-transform
一样使用here也不起作用,因为我需要将输出保存到文本文件中。
如何确保我可以在我的XSL转换中使用concat
和&
等特殊字符?
假设您在temp
下有一个名为/db/apps/
的eXist集合,其中包含以下文件:
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<testxml>
<name>Peter</name>
</testxml>
stylesheet.xsl
<?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"
version="2.0">
<xsl:template match="/">
<!-- Ampersand is not encoded: --> <xsl:value-of select="concat('Tom ', '& ', testxml/name)"/> -->
<!-- transformation fails: <xsl:value-of disable-output-escaping="yes" select="concat('Tom ', '&', testxml/name)"/> -->
<!-- Doesn't work obviously: <xsl:value-of select="concat('Tom ', '&', testxml/name)"/> -->
</xsl:template>
</xsl:stylesheet>
和
transformation.xq
xquery version "3.1";
declare function local:xml2tex() as xs:string
{
let $mime-type := "text/plain"
let $stylesheet := doc("/db/apps/temp/stylesheet.xsl")
let $serializationoptions := "method=text media-type=application/text"
let $doc := doc("/db/apps/temp/input.xml")
let $filename := (replace(util:document-name($doc), "\.xml$", "") || ".tex")
let $transform := transform:transform(
$doc,
$stylesheet,
(),
(),
$serializationoptions)
let $store := xmldb:store("/db/apps/temp", $filename, $transform, $mime-type)
return
$filename
};
local:xml2tex()
当您使用三个包含的transformation.xq
选项评估value-of select
时,您会看到工作的*.tex
文件的内容为Tom & Peter
,这不是预期的(将是Tom & Peter
)
根据eXist的transform:transform()
函数文档,这个函数返回一个node()
(或一个空序列)。因此,尽管您可能尝试将XSLT转换的结果强制为普通的旧字符串(正如您通过提供method=text
序列化参数所做的那样),但该函数仍会将此字符串作为节点返回 - 文本节点。
当您将文本节点传递给xmldb:store()
函数以存储文本文件(在您的情况下为.tex文件)时,序列化将再次发挥作用,因为文本节点必须序列化为eXist用于文本文件的二进制形式。默认的序列化方法是XML方法,它在序列化文本节点时转义字符串。
要测试此假设,请运行以下查询并检查生成的文件:
xmldb:store("/db", "01-text-node.txt", text { "Tom & Peter" } ),
xmldb:store("/db", "02-string.txt", "Tom & Peter" )
为了避免这个问题并确保使用text方法存储转换后的值,您应该使用几种方法之一来派生文本节点的字符串值 - 这里我将这些方法应用于您的$transform
变量:
cast as
运算符:$transform cast as xs:string
fn:string()
函数:string($transform)
或$transform/string()
。fn:serialize()
函数:serialize($transform, map { "method": "text" } )
更新:以下评论中报告的问题可能导致transform:transform()
函数返回多个node()
,这可能导致上述解决方案1和2导致意外的基数错误。解决方法是使用fn:string-join()
函数。解决方案3无需调整即可工