eXist-db 转换中的特殊字符和 xmldb:store
eXist-db special characters in transformation and xmldb:store
我有一个关于 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
和 &
等特殊字符?
编辑:添加示例
假设您在 /db/apps/
下有一个名为 temp
的 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()
当您使用包含的三个 value-of select
选项评估 transformation.xq
时,您会看到工作的那个生成一个 *.tex
文件,其内容 Tom & Peter
是 不是 的意图(即 Tom & Peter
)
根据 transform:transform()
的 eXist 函数文档,此函数 return 是一个 node()
(或空序列)。因此,尽管您可能试图将 XSLT 转换的结果强制为一个普通的旧字符串(就像您通过提供 method=text
序列化参数所做的那样),该函数仍将 return 这作为节点的字符串 - 文本节点。
当您将文本节点传递给 xmldb:store()
函数以存储文本文件(在您的情况下为 .tex 文件)时,序列化再次发挥作用,因为文本节点必须序列化到eXist 用于文本文件的二进制形式。默认的序列化方法是 XML 方法,它在序列化文本节点时对字符串进行转义。
为了检验这个假设,运行 下面的查询并检查生成的文件:
xmldb:store("/db", "01-text-node.txt", text { "Tom & Peter" } ),
xmldb:store("/db", "02-string.txt", "Tom & Peter" )
为避免此问题并确保使用文本方法存储转换后的值,您应该使用几种派生文本节点字符串值的方法之一 - 这里我将这些方法应用于您的 $transform
变量:
- 使用
cast as
运算符:$transform cast as xs:string
- 使用
fn:string()
函数:string($transform)
或$transform/string()
。
- 使用
fn:serialize()
函数:serialize($transform, map { "method": "text" } )
更新: 下面评论中报告的一个问题可能会导致 transform:transform()
函数 return 多于一个 node()
,这可能导致上述解决方案 1 和 2 导致意外的基数错误。解决方法是使用 fn:string-join()
函数。解决方案 3 无需调整即可工作。
我有一个关于 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
和 &
等特殊字符?
编辑:添加示例
假设您在 /db/apps/
下有一个名为 temp
的 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()
当您使用包含的三个 value-of select
选项评估 transformation.xq
时,您会看到工作的那个生成一个 *.tex
文件,其内容 Tom & Peter
是 不是 的意图(即 Tom & Peter
)
根据 transform:transform()
的 eXist 函数文档,此函数 return 是一个 node()
(或空序列)。因此,尽管您可能试图将 XSLT 转换的结果强制为一个普通的旧字符串(就像您通过提供 method=text
序列化参数所做的那样),该函数仍将 return 这作为节点的字符串 - 文本节点。
当您将文本节点传递给 xmldb:store()
函数以存储文本文件(在您的情况下为 .tex 文件)时,序列化再次发挥作用,因为文本节点必须序列化到eXist 用于文本文件的二进制形式。默认的序列化方法是 XML 方法,它在序列化文本节点时对字符串进行转义。
为了检验这个假设,运行 下面的查询并检查生成的文件:
xmldb:store("/db", "01-text-node.txt", text { "Tom & Peter" } ),
xmldb:store("/db", "02-string.txt", "Tom & Peter" )
为避免此问题并确保使用文本方法存储转换后的值,您应该使用几种派生文本节点字符串值的方法之一 - 这里我将这些方法应用于您的 $transform
变量:
- 使用
cast as
运算符:$transform cast as xs:string
- 使用
fn:string()
函数:string($transform)
或$transform/string()
。 - 使用
fn:serialize()
函数:serialize($transform, map { "method": "text" } )
更新: 下面评论中报告的一个问题可能会导致 transform:transform()
函数 return 多于一个 node()
,这可能导致上述解决方案 1 和 2 导致意外的基数错误。解决方法是使用 fn:string-join()
函数。解决方案 3 无需调整即可工作。