3

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

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

手动编辑生成的文件是不可能的,因为 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,无论使用 xslt1 还是 xslt2 的 iso,问题仍然存在):

<?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 甚至无法处理带有“添加属性后无法添加名称空间”或类似内容的 schematron(xslt1 的 iso 框架中的第 1534 行)。对我来说,唯一能够使用 queryBinding="exslt" 转换 schematron 的处理器仍然是 xsltproc。它也是我尝试过的唯一非 Java 处理器。在阅读了一些有问题的 XSL 之后,我注意到一条评论,其中声称该转换已使用 saxon9 进行了测试。所以这应该有效。

PS:为长篇文章道歉,但我认为举个例子很重要。

4

1 回答 1

4

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

在从中分离出有问题的 XSL 代码后,iso_schematron_skeleton_for_xslt1.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>

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

接下来(不,还没有完成)您必须意识到,当您在任何地方的测试中使用 function-available('exsl:node-set')" 时,Xalan 中似乎存在一个错误(这正是是在句柄命名空间中完成的)。即使这个函数已经被 Xalan 非常清楚地实现和支持,测试也会返回 false。所以不要使用它。我通过简单地假设这个函数存在并且没有在句柄命名空间模板(这也使该模板中的所有其他 xsl:choose 分支变得多余,因此我也简单地删除了这些分支)。下面您将找到我为从我的问题中获取示例架构以正确转换所做的所有更改。注意我不知道生成的样式表是否还有其他问题。这只解决了我的问题。

我修改的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 骨架被窃听。我很乐意向他们报告这一点,但他们的邮件列表似乎已经被垃圾邮件所困扰。

于 2012-02-11T21:15:15.507 回答