无法使用java XSLT处理器从Schematron架构生成有效的XSL样式表

时间:2012-02-07 09:23:53

标签: java xml xslt schematron

我正在尝试使用schematron验证我的实例文档,并且遇到Java XSLT处理器实现问题。当我尝试从我的schematron生成一个XSL时,即使是一个简单的XSL,我也会得到与我期望得到的结果不同的结果。

当使用xsltproc(cygwin)进行转换时,一切都没问题。但是使用Saxon-B 9.1.0.8,使用Saxon-PE 9.3.0.5的默认java 1.6实现或Oxygen IDE的XSLT调试器会生成无效的XSL文件。原因是包含extension-element-prefixes前缀的xsl:stylesheet元素的exsl属性,命名空间 未在任何地方声明。这样的样式表在使用时必然会失败。

由于在运行时在应用程序中生成了schematron,因此手动编辑生成的文件是不可能的。我必须做错事,对吧?我已将问题跟踪到iso_schematron_skeleton_for_saxon.xsl(或iso_schematron_skeleton_for_xslt1.xsl,具体取决于所使用的实现,是的,我尝试使用相同的最终结果)。尽管骨架清楚地创建了一个带有缺少命名空间的正确样式表,但它后来以某种方式被神奇地删除了。我不是一个真正的XSLT专家,所以我不知道我在这里做错了什么。我确定这只是我错过的一些愚蠢的事情。我想知道为什么下面输入的输出不同。

这是一个示例schematron,除了定义一些名称空间之外什么都不做(我希望这被认为是一个有效的模式):

<?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 for 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骨架部分被标记为实验..如果有必要,我愿意应用脏兮兮的工作来使其工作(除非我因为没有深入学习schematron而要求一些令人尴尬的事情)。有什么想法吗?

编辑 正如Martin在下面的评论中所建议的那样,我尝试使用纯XSLT 1.0处理器。我使用了xalan(编译和解释版本)和saxon 6.5.5。两个xalans都没有附加exsl名称空间。 Saxon甚至无法使用“在添加属性后添加命名空间”或类似的东西(xslt1的iso骨架中的第1534行)来处理schematron。能够使用queryBinding =“exslt”为我转换schematron的唯一处理器仍然是xsltproc。它也是我尝试过的唯一非java处理器。在阅读了一些有问题的XSL之后,我注意到了一条评论,其中声称已经使用saxon9测试了转换。所以这应该工作。

P.S。:长篇大论道歉,但我认为举一个这样的例子至关重要。

1 个答案:

答案 0 :(得分:4)

尽管我缺乏XSLT知识,但我自己通过调试来解决这个问题。此解决方案侧重于使用 Xalan (解释版本,xalan.jar或更精确org.apache.xalan.processor.TransformerFactoryImpl)作为首选的Java XSLT处理器。该解决方案需要对schematron骨架进行更改,并使其不可移植。

iso_schematron_skeleton_for_xslt1.xsl中隔离出有问题的XSL代码后,我发现“http://exslt.org/common”命名空间的原因只是从样式表中消失了,该样式表本应由转换(骨架是元样式表,这意味着它的输出也是样式表)。生成和生成的样式表都使用该EXSLT命名空间中的函数,并在单个XSL文件中的两个xsl:stylesheet元素中指定它似乎会使所有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>

因此,如果要将schematron转换为带有java的XSL,则需要避免这样做。由于骨架仅在一个地方使用EXSLT,因为exsl:node-set函数用于在句柄命名空间模板中构造命名空间属性,我通过简单地将此模板移动到外部样式表然后包含它来避免此问题在骨架里。如果仅为生成的xsl:stylesheet元素指定了消失的命名空间,则问题就会消失。至于为什么会发生这种情况......我完全不知道。也许更熟悉XSLT的人可以回答这个问题。

接下来(不,还没有完成)你必须意识到当你在任何地方使用function-available('exsl:node-set')“时,Xalan中似乎存在一个错误(其中正是在handle-namespace中完成了什么。。测试将返回false,即使Xalan已经非常清楚地实现并支持这个函数。所以不要使用它。我只是假设这个函数存在并且不执行在handle-namespace模板中测试(这也使得所有其他xsl:在该模板中选择分支冗余,所以我也只是删除了那些)。下面你会发现我为了从我的问题转换到示例模式所做的所有更改请注意,我不知道生成的样式表是否存在其他问题。这只能解决我的问题。

我修改的schematron骨架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>

这是包含文件的内容:

<!--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骨架在窃听。我很乐意向他们报告,但他们的邮件列表似乎已经被垃圾邮件所淹没。