转换和xmldb:store

时间:2019-02-21 14:49:16

标签: xslt xquery exist-db

我在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 ', '&amp;', ' Peter')"/>

但是保存回eXist的输出看起来像Tom $amp; Peter,而不是我期望的Tom & Peter。 当我指定disable-output-escaping="yes"时eXist终止并出现错误...

<xsl:value-of select="concat('Tom ', '&amp;', ' 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 ', '&amp; ', testxml/name)"/> -->
    <!-- transformation fails: <xsl:value-of disable-output-escaping="yes" select="concat('Tom ', '&amp;', 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 &amp; Peter,而不是目的是什么(应该是Tom & Peter

1 个答案:

答案 0 :(得分:2)

根据eXist的transform:transform()函数文档,此函数返回node()(或空序列)。结果,尽您可能会尝试将XSLT转换的结果强制为纯旧字符串(就像您通过提供method=text序列化参数所做的那样),该函数仍会将此字符串作为节点返回-文本节点。

当您将文本节点传递给xmldb:store()函数以存储文本文件(在您的情况下为.tex文件)时,序列化又开始起作用了,因为文本节点必须序列化为二进制形式eXist用于文本文件的文件。默认的序列化方法是XML方法,该序列化文本节点时会转义字符串。

要检验此假设,请运行以下查询并检查结果文件:

xmldb:store("/db", "01-text-node.txt", text { "Tom &amp; Peter" } ),
xmldb:store("/db", "02-string.txt", "Tom &amp; Peter" )

为避免此问题并确保使用text方法存储转换后的值,应使用几种派生文本节点的字符串值的方法之一-在这里,我将这些方法应用于您的$transform变量:

  1. 使用cast as运算符:$transform cast as xs:string
  2. 使用fn:string()函数:string($transform)$transform/string()
  3. 使用fn:serialize()函数:serialize($transform, map { "method": "text" } )

更新:以下评论中报告的问题可能导致transform:transform()函数返回多个node(),这可能导致上述解决方案1和2导致意外的基数错误。一种解决方法是使用fn:string-join()函数。解决方案3无需调整即可工作。