转换中的eXist-db特殊字符和xmldb:store

问题描述 投票:1回答:1

我有一个关于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 ', '&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"/>

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 ', '&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

xslt xquery exist-db
1个回答
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无需调整即可工

© www.soinside.com 2019 - 2024. All rights reserved.