XSD的Java Saxon有效子树

时间:2018-08-08 07:38:51

标签: java parsing xsd xml-parsing saxon

使用Saxon-HE,我想解析一个xsd文件,获取结果树,并从给定的元素名称中获取结果子树,以及所有必需的simpleType和complexType(都使用类型引用和引用),例如解析像这样的文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="PSS" xmlns=""
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element maxOccurs="unbounded" name="Assistito">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" name="IDCittadino" type="IDCittadino"/>
                <xs:element maxOccurs="unbounded" name="Struttura">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="CodiceStruttura" type="CodiceStruttura"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="IDCittadino">
        <xs:restriction base="xs:string">
            <xs:minLength value="20"/>
            <xs:maxLength value="32"/>
        </xs:restriction>
    </xs:simpleType>   
    <xs:simpleType name="CodiceStruttura">
        <xs:restriction base="xs:string">
            <xs:minLength value="1"/>
            <xs:maxLength value="8"/>
        </xs:restriction>
    </xs:simpleType>   
</xs:schema>

我需要从名称为“ Struttura”的元素中获取子树,还需要从名称为“ CodiceStruttura”的simpleType中获取子树,例如:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="PSS" xmlns=""
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Struttura">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="CodiceStruttura" type="CodiceStruttura"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="CodiceStruttura">
        <xs:restriction base="xs:string">
            <xs:minLength value="1"/>
            <xs:maxLength value="8"/>
        </xs:restriction>
    </xs:simpleType>   
</xs:schema>

注释

  • 一般而言,要作为一致性的xsd应该保留xs:element中使用的所有类型,但是您也可以使用“ ref attribute”,这也应该考虑在内
  • 我不想使用jaxb或类似文件生成类,因为xsd文件每次都会更改,因此我不能使用类生成

预先感谢

2 个答案:

答案 0 :(得分:1)

通常,我不建议使用模式文档的原始XML,建议使用模式编译器生成的模式组件模型,因为否则您将发现自己(a)复制了模式编译器,或者(b)弄错了,并且没有正确处理所有模式。

您可以通过多种方式以编程方式访问架构组件模型。 Saxon提供了两种方法(但都需要Saxon-EE)。 (a)您可以使用Saxon的模式处理器(使用com.saxonica.Validate -xsd:schema.xsd -scmout:schema.scm)输出模式组件模型的XML表示形式。 (b)您可以使用一组扩展功能(从saxon:schema()开始,从XSLT或XQuery访问模式组件模型。

作为替代方案,Xerces模式处理器为其内部模式组件模型提供了Java API,您也许可以使用Xalan(或实际上是Saxon)扩展功能来访问此API。

在所有这些情况下,提供的“架构组件模型”非常接近W3C XSD规范中描述的抽象架构组件模型。与使用原始模式文档的主要区别包括:(a)所有导入,包含和跨组件引用均已解决; (b)所有违约均已扩大; (c)模型组和属性组已扩展。

答案 1 :(得分:0)

我不确定没有任何基于模式解析/模式的XSLT或XQuery处理或模式对象模型的Saxon 9 HE是否适合该任务,它仅有的就是XSLT 3或XQuery 3.1,因此您需要使用XSLT 3和xsl:key之类的语言的功能来遵循任何typeref的交叉引用。

尝试为我创建的type实现这一目标

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:param name="element-to-search" as="xs:QName" select="xs:QName('Struttura')"/>

  <xsl:key name="element-ref" match="xs:element" use="resolve-QName(@name, .)"/>

  <xsl:key name="type-ref" match="xs:complexType | xs:simpleType" use="resolve-QName(@name, .)"/>

  <xsl:variable name="start-element" select="key('element-ref', $element-to-search)"/>

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:mode name="flatten" on-no-match="shallow-skip"/>

  <xsl:template match="/*">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates select="$start-element"/>
          <xsl:apply-templates select="$start-element//xs:element" mode="flatten"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="xs:element[@type and key('type-ref', resolve-QName(@type, .))]" mode="flatten">
      <xsl:apply-templates select="key('type-ref', resolve-QName(@type, .))"/>
  </xsl:template>

</xsl:stylesheet>

为您的示例输入创建(在https://xsltfiddle.liberty-development.net/eiZQaFw的在线示例)的输出

<xs:schema xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           id="PSS">
   <xs:element maxOccurs="unbounded" name="Struttura">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="CodiceStruttura" type="CodiceStruttura"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:simpleType name="CodiceStruttura">
      <xs:restriction base="xs:string">
         <xs:minLength value="1"/>
         <xs:maxLength value="8"/>
      </xs:restriction>
   </xs:simpleType>
</xs:schema>

因此,该方法找到了所引用的简单类型并添加了它,并为ref属性使用了单独的键,您也许也可以添加它们,并且如果有的话,也可能是可行的(也许有些递归)一个没有包含和导入的单一模式模块,以及迈克尔·凯(Michael Kay)提到的更高级的模式功能。我不确定它是否会对模式进行任何健壮的处理,模式语言是否复杂,并且仅按您的要求进行复制也会造成问题(如您所见,maxOccurs="unbounded"已通过简单方法进行了复制,您将需要添加一个模板,以禁止您在顶层放置的任何内容。

我也不确定通过将内联元素拉到顶层来构造无效的东西是否容易,如果您选择一个内联的局部作用域元素foo作为起点,会发生什么但是还存在一个全局声明的且在其他地方引用的foo元素吗?