Xslt 转换和xmldb:store中存在数据库特殊字符
我有一个关于eXist db 4.5中输出转义的问题: 我正在使用Xslt 转换和xmldb:store中存在数据库特殊字符,xslt,xquery,exist-db,Xslt,Xquery,Exist Db,我有一个关于eXist db 4.5中输出转义的问题: 我正在使用transform:transform(带有$serialization options=方法=文本媒体类型=应用程序/text)和xmldb:store(带有$mime-type=文本/plain)将XSL转换的输出保存回数据库。在我使用的xslt样式表中 <xsl:value-of select="concat('Tom ', '&', ' Peter')"/> 像建议的那样使用transform
transform:transform
(带有$serialization options
=方法=文本媒体类型=应用程序/text
)和xmldb:store
(带有$mime-type
=文本/plain
)将XSL转换的输出保存回数据库。在我使用的xslt样式表中
<xsl:value-of select="concat('Tom ', '&', ' Peter')"/>
像建议的那样使用transform:stream transform
也不起作用,因为我需要将输出保存到文本文件中
如何确保在XSL转换中可以使用concat
和特殊字符,如&
编辑:添加示例 假设您在
/db/apps/
下有一个名为temp
的现有集合,其中包含以下文件:
input.xml
及
transformation.xq
当您使用select选项中包含的三个
值评估transformation.xq
时,您会看到工作文件生成一个*.tex
文件,其内容为Tom&;Peter
这不是预期的(即Tom&Peter
)根据eXist的函数文档,此函数返回一个节点()
(或一个空序列)。因此,尽管您可能会试图强制XSLT转换的结果成为一个普通的旧字符串(正如您通过提供method=text
serialization参数所做的那样),该函数仍然会将该字符串作为一个节点(一个文本节点)返回
当您将文本节点传递给xmldb:store()
函数以存储文本文件(在您的例子中是.tex文件)时,序列化将再次发挥作用,因为文本节点必须序列化为现有用于文本文件的二进制形式。默认的序列化方法是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()
函数返回多个节点()
,这可能导致上述解决方案1和2导致意外的基数错误。解决方法是使用fn:string-join()
函数。解决方案3无需调整即可工作。如果您可以发布一个最小的、自包含的、可复制的示例来演示该现象,这将非常有帮助。那可能吗?然后我们可以看看解决这个问题需要什么。嗨@joewiz,我希望我的例子足够了!的确如此!我能够重现你的问题并弄清问题的真相。当你有机会看一看,请让我知道,如果有什么在我的答案是不清楚的。谢谢!选项1和2不起作用,因为转换后我们有多个textnode;获取了类似的错误,参数1的实际基数与函数的signature:string($arg as item()?)xs:string中声明的基数不匹配。期望基数:0或1,得到713。
使用fn:serialize()
函数(选项3)有效,但我们最终使用了字符串连接($transform)
,这也有效!我接受你的答案,也许你可以添加第四个选项?嗯,很高兴你找到了字符串连接的解决方法,但我很困惑transform:transform的结果可能不是(零或-)一个节点。上面写的代码真的产生了这个结果吗?如果是这样,我们可能有一个未知的错误存在。任何进一步的信息,你可以提供将是有益的!transformation.xq
的代码与我们在eXist中使用的代码完全相同。然而,我们的input.xml
和stylesheet.xsl
显然要复杂得多;)如果对你有帮助的话,我可以把那些文件寄给你!那太好了。你能把它们写进新的一期吗?理想情况下,测试将演示transform:transform()
函数返回的节点数超过1个node()!
<?xml version="1.0" encoding="UTF-8"?>
<testxml>
<name>Peter</name>
</testxml>
<?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>
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()
xmldb:store("/db", "01-text-node.txt", text { "Tom & Peter" } ),
xmldb:store("/db", "02-string.txt", "Tom & Peter" )