我可以创建一个XSD架构,在所有复杂类型上放置属性吗?

时间:2009-05-31 16:22:11

标签: xml xsd schema xml-attribute

我想创建一个XSD,它定义一个属性,该属性可以放在来自其他模式的元素或不在任何模式中的元素上。例如,架构看起来像这样:

<xs:schema id="MySchema"
    targetNamespace="http://tempuri.org/MySchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/MySchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:attribute name="myAttribute" />
</xs:schema>

文档看起来像这样:

<someElement xmlns="http://tempuri.org/OtherSchema" xmlns:m="http://tempuri.org/MySchema">
  <someOtherElement someAttribute="value" m:myAttribute="value2" />
</someElement>

此示例中的“OtherSchema”如下所示:

<xs:schema id="OtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="someElement">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" name="someOtherElement">
          <xs:complexType>
            <xs:attribute name="someAttribute" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

可以从http://dl.getdropbox.com/u/407740/SchemaTest.zip下载完整的示例,包括执行验证的C#控制台应用程序。我的目标是在不必修改“OtherSchema”的情况下进行验证。这可能吗?

4 个答案:

答案 0 :(得分:1)

我必须添加一个包装器,将两个不同的模式导入一个(因为xmllint只接受一个xml模式):

<xs:schema id="Wrapper" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import schemaLocation="MySchema.xsd" namespace="http://tempuri.org/MySchema"/>
  <xs:import schemaLocation="OtherSchema.xsd" namespace="http://tempuri.org/OtherSchema"/>
</xs:schema>

我可以获得类似问题的唯一方法是编辑OtherSchema,xsd(问题不允许),所以附加一个属性通配符(在现有的之后):

 <xs:attribute name="someAttribute" />
 <xs:anyAttribute namespace="##other"/>

我不足以让XML Schema的专家说“这是不可能的”,但对我来说似乎是不可能的。

您的提案存在的一个问题是您未指定应在何处显示新属性。通常,如果声明属性(或复杂元素,模型组等),您可以自由引用它。如果您没有明确引用它,它就没有效果。因此,我认为您的提案将被视为已声明但未提及的属性。

你真正想要的是一种说“将此属性添加到每个现有complexType”的方法 - 但你不这么说。并且,不幸的是,似乎没有办法说出这一点。 (甚至没有办法说“将此属性添加到此特定的现有complexType” - 您必须将其包含在原始定义中或根本不包含。)

部分执行此操作的一种方法是在另一个模式中使用<redefine>类型 - 我将在第二个答案中添加此类型。

答案 1 :(得分:1)

您可以重新定义架构,随意扩展它们。通过这种方式,您可以修改现有模式的定义,而无需实际更改文件。但是它不适用于给定的示例,因为无法重新定义元素(只有复杂类型等等 http://www.w3.org/TR/xmlschema-1/#element-redefine)。因此,我已将您的示例分解为显式complexTypes,因此它们会被公开以进行重新定义。

<强> RedefineOtherSchema.xsd:

<xs:schema id="RedefineOtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:m="http://tempuri.org/MySchema">          <!-- for the ref -->

  <xs:import schemaLocation="MySchema.xsd"
    namespace="http://tempuri.org/MySchema"/>       <!-- import -->

  <xs:redefine schemaLocation="OtherSchema.xsd">    <!-- redefine -->
    <xs:complexType name="SomeOtherElement">
      <xs:complexContent>
        <xs:extension base="SomeOtherElement">
          <xs:attribute ref="m:myAttribute" />      <!-- the ref -->
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>
</xs:schema>

<强> OtherSchema:

<xs:schema id="OtherSchema"
    targetNamespace="http://tempuri.org/OtherSchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/OtherSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="someElement" type="SomeElement"/>

    <xs:complexType name="SomeElement">
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded"
                    name="someOtherElement" type="SomeOtherElement"/>
      </xs:sequence>
    </xs:complexType>

    <xs:complexType name="SomeOtherElement">
      <xs:attribute name="someAttribute" />
    </xs:complexType>
</xs:schema>

MySchema:(未更改)

<xs:schema id="MySchema"
    targetNamespace="http://tempuri.org/MySchema"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/MySchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:attribute name="myAttribute"/>
</xs:schema>

为什么<complexContent> 重新定义必须是现有类型的扩展(或限制) - 它是如何修改先前的定义。扩展必须在<complexContent>(我相信)。

为什么<import> 您无法在xsd中的多个命名空间中定义事物(只有一个“targetNamespace”)。但是你可以通过从另一个xsd导入定义来解决这个问题(然后你没有“定义”它)。 [还有另一种方式吗?]

HTH: - )

答案 2 :(得分:0)

这正是NVDL(基于命名空间的验证和调度语言)所提供的。它允许组合多个模式/词汇表来验证文档,而无需更改这些模式。 NVDL是ISO标准。

处理您案例的工作NVDL脚本位于

之下
<rules xmlns="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0" startMode="other">
  <mode name="other">
    <namespace ns="http://tempuri.org/OtherSchema">
      <validate schema="other.xsd" useMode="validateMyAttributes"/>
    </namespace>
  </mode>
  <mode name="validateMyAttributes">
    <namespace ns="http://tempuri.org/MySchema" match="attributes">
      <validate schema="my.xsd"/>
    </namespace>
  </mode>
</rules>

基本上它说使用other.xsd架构验证了... tempuri.org/OtherSchema命名空间的内容以及来自... tempuri.org/MySchema和my.xsd架构的属性。

有关NVDL的更多信息,请访问www.nvdl.org。上面的脚本是用oNVDL测试的。

答案 3 :(得分:-1)

考虑xsi:nil,xsi:schemaLocation和xsi:noNamespaceSchemaLocation。答案是肯定的。

也不会花很长时间尝试并看到它。


您在架构中缺少targetNamespace。试试这个:

<xs:schema xmlns="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="MySchema">
  <xs:attribute name="myAttribute" />
</xs:schema>