специальные символы eXist-db в преобразовании и xmldb: store - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть вопрос, касающийся выхода в eXist-db 4.5:

Я использую transform:transform$serialization-options = method=text media-type=application/text) и xmldb:store$mime-type= text/plain) чтобы сохранить выходные данные преобразования XSL обратно в базу данных.Внутри моей таблицы стилей xslt я использую

<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, как предложено здесь тоже не работает, потому что мне нужно сохранить вывод втекстовый файл.

Как я могу убедиться, что могу использовать concat и специальные символы, такие как &, в своем XSL-преобразовании?


Редактировать: Добавлен пример

Допустим, у вас есть коллекция eXist с именем temp в /db/apps/ со следующими файлами:

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 голосов
/ 23 февраля 2019

Согласно документации по функциям eXist для transform:transform(), эта функция возвращает node() (или пустую последовательность).В результате, сколько бы вы ни пытались заставить результат преобразования XSLT быть простой старой строкой (как вы сделали, указав параметр сериализации method=text), функция все равно будет возвращать эту строку как узел - aтекстовый узел.

Когда вы передаете текстовый узел в функцию 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" )

Чтобы этого избежатьпроблема и убедитесь, что преобразованное значение хранится с использованием текстового метода, вы должны использовать один из нескольких методов получения строкового значения текстового узла - здесь я применяю эти методы к вашей $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 работает без настройки.

...