Невозможно сгенерировать действительную таблицу стилей XSL из схемы Schematron с использованием процессора Java XSLT - PullRequest
3 голосов
/ 07 февраля 2012

Я пытаюсь проверить мои экземпляры документов с помощью schematron и у меня возникают проблемы с реализациями процессора Java XSLT.Когда я пытаюсь сгенерировать XSL из своего схематрона, даже простого, я получаю результаты, отличные от ожидаемых.

Когда xsltproc (cygwin) используется для преобразования, все в порядке.Но, используя Saxon-B 9.1.0.8, стандартная реализация java 1.6 или отладчик XSLT Oxygen IDE с Saxon-PE 9.3.0.5 генерируют недопустимый XSL-файл.Причиной является атрибут extension-element-prefixes элемента xsl:stylesheet, содержащего префикс exsl, для которого пространство имен равно , нигде не объявлено .Такая таблица стилей обречена на неудачу при использовании.

Редактирование сгенерированных файлов вручную исключено, поскольку schematron генерируется в приложении во время выполнения.Я должен делать что-то не так, верно?Я отследил проблему в iso_schematron_skeleton_for_saxon.xsl (или iso_schematron_skeleton_for_xslt1.xsl, в зависимости от используемой реализации, да, я пробовал оба с одинаковым конечным результатом).Хотя скелет явно создает правильную таблицу стилей с отсутствующим пространством имен, позже он каким-то волшебным образом удаляется.Я на самом деле не эксперт по XSLT, поэтому я понятия не имею, что я делаю здесь не так.Я уверен, что это просто глупость, которую я где-то пропустил.Я хотел бы знать, почему выходные данные для ввода ниже отличаются.

Вот пример схемы, которая ничего не делает, но определяет некоторые пространства имен (надеюсь, это считается допустимой схемой):

<?xml version="1.0" encoding="utf-8"?>
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" 
    queryBinding="exslt">
   <sch:ns uri="http://exslt.org/dynamic" prefix="dyn"/>
   <sch:ns xmlns:rng="http://relaxng.org/ns/structure/1.0" 
      xmlns:nma="urn:ietf:params:xml:ns:netmod:dsdl-annotations:1" 
      uri="urn:ietf:params:xml:ns:yang:ietf-inet-types" 
      prefix="inet"/>
   <sch:ns xmlns:rng="http://relaxng.org/ns/structure/1.0" 
      xmlns:nma="urn:ietf:params:xml:ns:netmod:dsdl-annotations:1" 
      uri="urn:ietf:params:xml:ns:yang:ietf-ipfix-psamp" 
      prefix="ipfix"/>
   <sch:ns xmlns:rng="http://relaxng.org/ns/structure/1.0" 
      xmlns:nma="urn:ietf:params:xml:ns:netmod:dsdl-annotations:1" 
      uri="urn:ietf:params:xml:ns:yang:ietf-yang-types" 
      prefix="yang"/>
   <sch:ns xmlns:rng="http://relaxng.org/ns/structure/1.0" 
      xmlns:nma="urn:ietf:params:xml:ns:netmod:dsdl-annotations:1" 
      uri="urn:ietf:params:xml:ns:netconf:base:1.0" 
      prefix="nc"/>   
</sch:schema>

Вот фрагмент кода, который я получаю от процессоров Java XSLT (этот от Oxygen, не имеет значения, используется ли iso для xslt1 или xslt2, проблема сохраняется):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--This XSLT was automatically generated from a Schematron schema.-->
<xsl:stylesheet xmlns:sch="http://www.ascc.net/xml/schematron" 
    xmlns:set="http://exslt.org/sets"
    xmlns:str="http://exslt.org/strings"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    xmlns:dyn="http://exslt.org/dynamic"
    xmlns:iso="http://purl.oclc.org/dsdl/schematron"
    xmlns:math="http://exslt.org/math"
    xmlns:random="http://exslt.org/random"
    xmlns:regexp="http://exslt.org/regular-expressions"
    xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types"
    xmlns:ipfix="urn:ietf:params:xml:ns:yang:ietf-ipfix-psamp"
    xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types"
    xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
    extension-element-prefixes="date dyn exsl math random regexp set str"
    version="1.0">
    <!--Removed in favor of brevity.-->
</xsl:stylesheet>

Вот что генерирует xsltproc ичто бы я хотел, чтобы java тоже:

<?xml version="1.0" standalone="yes"?>
<!--This XSLT was automatically generated from a Schematron schema.-->
<axsl:stylesheet 
    xmlns:date="http://exslt.org/dates-and-times" 
    xmlns:dyn="http://exslt.org/dynamic" 
    xmlns:exsl="http://exslt.org/common" 
    xmlns:math="http://exslt.org/math" 
    xmlns:random="http://exslt.org/random" 
    xmlns:regexp="http://exslt.org/regular-expressions" 
    xmlns:set="http://exslt.org/sets" 
    xmlns:str="http://exslt.org/strings" 
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:sch="http://www.ascc.net/xml/schematron" 
    xmlns:iso="http://purl.oclc.org/dsdl/schematron" 
    xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types" 
    xmlns:ipfix="urn:ietf:params:xml:ns:yang:ietf-ipfix-psamp" 
    xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types" 
    xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" 
    extension-element-prefixes="date dyn exsl math random regexp set str" 
    version="1.0">
    <!--Removed in favor of brevity.-->
</axsl:stylesheet>

Как вы видите, на выходе Java отсутствует пространство имен exsl для соответствующего префикса.Я понимаю, что часть iso-скелета, которая должна обрабатывать пространства имен, помечена как экспериментальная. Я готов применить грязные хаки, чтобы заставить это работать, если это необходимо (если я не спрашиваю что-то неловкое из-за неисследования схематизма подробно).).Любые идеи?

Редактировать: , как предложил Мартин в комментарии ниже, я пытался использовать чистый процессор XSLT 1.0.Я использовал xalan (как скомпилированные, так и интерпретирующие версии) и saxon 6.5.5.Ни один из xalans не добавляет пространство имен exsl.Saxon даже не может обработать схему с «не может добавить пространство имен после добавления атрибутов» или что-то подобное (строка 1534 в iso-скелете для xslt1).Единственным процессором, способным преобразовать схематрон с помощью queryBinding = "exslt" для меня, остается xsltproc.Это также единственный не Java-процессор, который я пробовал.Прочитав немного обидного XSL, я заметил комментарий, в котором утверждается, что преобразование было протестировано с помощью saxon9.Так что это ДОЛЖНО работать.

PS: извиняюсь за длинный пост, но я думаю, что жизненно важно привести пример этого.

1 Ответ

4 голосов
/ 12 февраля 2012

Я взломал эту проблему, отладив ее сам, несмотря на отсутствие знаний XSLT.Это решение фокусируется на использовании Xalan (интерпретирующая версия, xalan.jar или, если быть более точным org.apache.xalan.processor.TransformerFactoryImpl) в качестве предпочтительного процессора Java XSLT.Решение требует внесения изменений в скелет схематора, а также его непереносимость.

После выделения проблемного фрагмента кода XSL из iso_schematron_skeleton_for_xslt1.xsl я выяснил, что является причиной просто исчезновения пространства имен "http://exslt.org/common""из таблицы стилей, которая должна была быть сгенерирована преобразованием (скелет является мета-таблицей стилей, что означает, что его вывод также является таблицей стилей). И генерирующая, и сгенерированная таблица стилей используют функции из этого пространства имен EXSLT и задают его в двух xsl: элементы таблицы стилей внутри одного файла XSL, кажется, заставляют все Java-процессоры XSLT взрываться. Серьезно. Если вы сделаете это (см. пример ниже), пространство имен в сгенерированной таблице стилей просто исчезнет.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
 xmlns:exsl="http://exslt.org/common"
 extension-element-prefixes="exsl">
    <xsl:output method="xml" omit-xml-declaration="yes" />
    <xsl:strip-space elements="*"/>
    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

    <xsl:template match="/">
        <xsl:call-template name="disappearance-act" />
    </xsl:template>

    <xsl:template name="disappearance-act">
        <axsl:stylesheet
        xmlns:exsl="http://exslt.org/common"
        extension-element-prefixes="exsl" >
            <xsl:attribute name="version">1.0</xsl:attribute>
        </axsl:stylesheet>
    </xsl:template>
</xsl:stylesheet>

Итак, вы 'Вам нужно будет избегать этого, если вы хотите преобразовать ваш схематрон в XSL с Java. Так как скелет использует EXSLT только в одном месте из-за функции exsl: node-set, которая используется для создания атрибута пространства имен в handle-НамаШаблон espace Я избежал этой проблемы, просто переместив этот шаблон во внешнюю таблицу стилей, а затем включив его в скелет.Если исчезающее пространство имен указано только для сгенерированного элемента xsl: stylesheet, проблема просто исчезнет.Что касается того, почему это может происходить ... Я понятия не имею.Возможно, кто-то более опытный в XSLT сможет ответить на этот вопрос.

Далее (нет, еще не сделано) вы должны знать о том факте, что в Xalan возникает ошибка, когда вы используете функцию available ('exsl: node-set ') "в тесте где угодно (это именно то, что делается в дескрипторном пространстве имен). Тест вернет false, даже если эта функция довольно четко реализована и поддерживается Xalan. Поэтому не используйте это.Я решил ее, просто предположив, что эта функция существует, и не выполняя тест в шаблоне handle-namespace (это также делает все остальные xsl: выбирать ветви в этом шаблоне избыточными, поэтому я просто удалил их тоже). Ниже вы найдете всеизменения, которые я сделал, чтобы получить пример схемы из моего вопроса для правильного преобразования. Обратите внимание, что я не знаю, есть ли другие проблемы с сгенерированной таблицей стилей. Это только решает проблему в моем вопросе.

ЧастиСхематрон скелет XSL, который я изменил:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
 xmlns:sch="http://www.ascc.net/xml/schematron"
 xmlns:iso="http://purl.oclc.org/dsdl/schematron" >
     <!--Removed no longer neccessary stuff from root stylesheet-->
    <xsl:output method="xml" omit-xml-declaration="no" standalone="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

     <!--This was added.-->
    <xsl:include href="namespaces.xsl"/>

    <xsl:template match="/">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="iso:schema[@queryBinding='exslt']">
        <axsl:stylesheet
        xmlns:date="http://exslt.org/dates-and-times"
        xmlns:dyn="http://exslt.org/dynamic"
        xmlns:exsl="http://exslt.org/common"
        xmlns:math="http://exslt.org/math"
        xmlns:random="http://exslt.org/random"
        xmlns:regexp="http://exslt.org/regular-expressions"
        xmlns:set="http://exslt.org/sets"
        xmlns:str="http://exslt.org/strings"
        extension-element-prefixes="date dyn exsl math random regexp set str" >

            <xsl:apply-templates select="iso:ns"/>
            <xsl:attribute name="version">1.0</xsl:attribute>
     <!--Irrelevant changes here in order to make this stylesheet runnable.-->
        </axsl:stylesheet>
    </xsl:template>

    <xsl:template match="iso:ns">
        <xsl:call-template name="handle-namespace" />
    </xsl:template>

    <!--handle-namespace template was removed here-->

</xsl:stylesheet>

Это содержимое вклФайл ude:

<!--namespaces.xsl-->
<!--The include stylesheet which handles the namespaces from schematron.-->
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:exsl="http://exslt.org/common"
 extension-element-prefixes="exsl">

    <xsl:template name="handle-namespace">
        <xsl:variable name="ns-dummy-elements">
            <xsl:element name="{@prefix}:dummy" namespace="{@uri}"/>
        </xsl:variable>
        <xsl:variable name="p" select="@prefix"/>
        <xsl:copy-of select="exsl:node-set($ns-dummy-elements)
                                  /*/namespace::*[local-name()=$p]"/>
    </xsl:template>

</xsl:stylesheet>

Это только обходной путь для моей проблемы.Я не считаю это полным ответом на мой вопрос, поэтому я не буду помечать его как ответивший, пока кто-то не объяснит, почему это пространство имен исчезает.

Редактировать: после публикации вопроса всписок рассылки xalan-j и прочтя его - EXSLT - я пришел к выводу, что исчезающее пространство имен - это то, что должно произойти.Атрибут extension-element-prefixes используется для предотвращения вывода пространств имен расширения в дерево результатов.Еще раз я обнаружил, что xsltproc не соответствует спецификациям XSLT 1.0.Это также означает, что скелет iso schematron находится в баге.Я бы с радостью сообщил об этом им, но их список рассылки, похоже, уступил спаму.

...