我在eXist-db 4.5中有一个关于输出转义的问题:
我正在使用transform:transform
(带有$serialization-options
= method=text media-type=application/text
)和xmldb:store
(带有$mime-type
= text/plain
)来保存输出XSL转换回数据库。在我的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"/>
像建议的here那样使用transform:stream-transform
也不起作用,因为我需要将输出保存到文本文件中。
如何确保在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
)
答案 0 :(得分:2)
根据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无需调整即可工作。