Шлейфовое соединение XSLT в Saxon для удаления CDATA из действительного XML перед вторым проходом

У меня возникла интересная проблема, когда я пытаюсь последовательно соединить два преобразования по порядку (с использованием XSLT 2.0), чтобы удалить элементы CDATA из исходного XML на первом проходе, чтобы его можно было проанализировать как XML во втором. Хотя я сомневаюсь, что это повлияет на результат, я использую параметр начального шаблона в Saxon 9 HE и функцию collection (), чтобы собрать несколько XML-документов (одинаковые пространства имен) в переменную перед тем, как подвергнуть ее преобразованию. Стоит отметить, что сейчас я даже не могу заставить это работать с одним документом.

Мои входные документы:

<root>
    <blah>
        <![CDATA[<elementA att="A"><elementB att="B">Text</elementB></elementA>]]>
    </blah>
</root>

Моя попытка XSLT:

    <!-- Collect all XML files in $input folder for processing -->
    <xsl:variable name="xml" select="collection(concat($input,'?select=*.*ml;recurse=no;on-error=ignore'))"/>

    <!-- Initial template is called from the saxon command line using the -it:process option -->
    <xsl:template name="process">
        <!-- First pass -->
        <xsl:variable name="pass1xml">
            <xsl:apply-templates select="$xml" mode="pass1"/>
        </xsl:variable>
        <!-- First pass output -->
        <xsl:result-document href="{concat($output,'\pass1.xml')}" method="xml" indent="yes">
            <xsl:copy-of select="$pass1xml"/>
        </xsl:result-document>
        <!-- Second pass -->
        <xsl:apply-templates select="$pass1xml" mode="pass2"/>
    </xsl:template>

    <!-- First pass: copy everything -->
    <xsl:template match="@* | node()" mode="pass1">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" mode="pass1"/>
        </xsl:copy>
    </xsl:template>

    <!-- First pass: strip CDATA from element -->
    <xsl:template match="blah" mode="pass1">
        <xsl:copy>
            <xsl:value-of select="." disable-output-escaping="yes"/>
        </xsl:copy>
    </xsl:template>

    <!-- Second pass using $pass1xml variable -->
    <xsl:template match="root" mode="pass2">
        <!-- Second pass output -->
        <xsl:result-document href="{concat($output,'\pass2.xml')}" method="xml" indent="yes">
            <xsl:apply-templates select="descendant::elementA" mode="elementA"/>
        </xsl:result-document>      
    </xsl:template>

...etc (continue with second pass)...

Желаемый результат первого прохода:

<root>
    <blah>
        <elementA att="A">
            <elementB att="B">Text</elementB>
        </elementA>
    </blah>
</root>

То, что я сейчас вижу в моем pass1.xml (результат первого прохода - несмотря на использование disable-output-escaping = "yes"), - это экранированный XML, который, очевидно, не является XPATHable в pass2:

<root>
    <blah>
        &lt;elementA att="A"&gt;&lt;elementB att="B"&gt;Text&lt;/elementB&gt;&lt;/elementA&gt;
    </blah>
</root>

К сожалению, я не могу изменить исходный документ, чтобы удалить CDATA (я ценю, что это решит мою проблему). XML в CDATA тоже всегда будет правильно сформирован, поэтому я не сомневаюсь в его удалении. Возможно, я неправильно понимаю подход гирляндной цепи, что означает, что то, чего я пытаюсь достичь, невозможно - в любом случае я очень хочу научиться.

Большое спасибо за ваше время и советы - это очень важно!


person Aaron    schedule 29.04.2014    source источник


Ответы (1)


disable-output-escaping - это функция сериализации, поэтому она не помогает для узлов в памяти, которые вы хотите передать на второй шаг преобразования в той же таблице стилей, вам нужно будет использовать две таблицы стилей, где результат первого сериализуется первым перед тем, как скармливать второй.

Как вы упомянули Saxon, я бы, тем не менее, рассмотрел возможность использования коммерческих версий и функций расширения или функций XSLT / XPath 3.0, таких как [parse-xml][1] или [parse-xml-fragment][2], предлагаемых для простого анализа и обработки содержимого, например.

<xsl:template match="blah">
  <xsl:apply-templates select="parse-xml-fragment(.)/node()"/>
</xsl:template> 

В качестве альтернативы в Saxon 9.1 B есть функция расширения, доступная даже в версии с открытым исходным кодом.

person Martin Honnen    schedule 29.04.2014
comment
Спасибо за ответ, теперь я понимаю концепцию намного лучше. Я дал SaxonB шанс (для других, кому интересно: sourceforge.net/projects/saxon / files / Saxon-B) - отличная идея, но для меня в командной строке (командном файле) отсутствует -catalog, поэтому я бы поменял одну задачу на другую. Я тоже стремлюсь оставаться открытым исходным кодом на данный момент (мне нужно что-то, чем я могу широко поделиться), поэтому я запускаю два преобразования из командной строки. Еще раз спасибо! - person Aaron; 29.04.2014