从现有模式扩展复杂类型

时间:2010-07-29 07:34:14

标签: .net validation xsd

我需要使用新元素扩展现有的XML文档,而不会失去根据未更改的原始模式和我定义的扩展模式验证它的能力。

例如,假设我想将CodePrice元素添加到现有的Book文档中,如下所示:

<aa:Book xmlns:aa="http://www.aa.com"
         xmlns:bb="http://www.bb.com">
  <aa:Title>Complete Works</aa:Title>
  <aa:Author>Shakespeare</aa:Author>
  <bb:Code>98</bb:Code>
  <bb:Price>31.6</bb:Price>
</aa:Book>

原始架构(我无法改变)看起来像这样:

<xs:schema targetNamespace="http://www.aa.com"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://www.aa.com"
           elementFormDefault="qualified">
  <xs:element name="Book" type="Book--type" />
  <xs:complexType name="Book--type">
    <xs:sequence>
      <xs:element name="Title" type="xs:string" />
      <xs:element name="Author" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

如何创建定义这些新元素的新模式,以便包含这两个模式的SchemaSet可以成功验证上面的扩展XML文档?

我尝试了以下常用的复杂类型扩展模式:

<xs:schema targetNamespace="http://www.bb.com"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://www.bb.com"
           xmlns:aa="http://www.aa.com"
           elementFormDefault="qualified">
  <xs:import namespace="http://www.aa.com" />
  <xs:complexType name="Book--type">
    <xs:complexContent>
      <xs:extension base="aa:Book--type">
        <xs:sequence>
          <xs:element name="Code" type="xs:int" />
          <xs:element name="Price" type="xs:double" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

然而,这会导致错误,指出元素aa:Book没有定义子元素bb:Code,这完全有道理。

这甚至可能吗?

供参考,以下是我用来验证文档的代码:

var fail = new ValidationEventHandler((sender, e) => Debug.Fail(e.Message));
var schemaSet = new XmlSchemaSet();
schemaSet.Add(XmlSchema.Read(new StringReader(original), fail));
schemaSet.Add(XmlSchema.Read(new StringReader(extension), fail));
var settings = new XmlReaderSettings
    {
        ValidationType = ValidationType.Schema,
        Schemas = schemaSet
    };
settings.ValidationEventHandler += fail;
using (var stream = File.OpenRead(fileName))
using (var reader = XmlReader.Create(stream, settings))
{
    while (reader.Read()) {}
}

2 个答案:

答案 0 :(得分:1)

事实证明xs:redefine正是我所寻找的。它允许您重新定义新架构中的现有元素,而无需触及原始架构或正在验证的文档。

使用我的原始示例,可以使用以下两种模式扩展一本书:

<xs:schema targetNamespace="http://www.bb.com"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://www.bb.com"
           elementFormDefault="qualified">
  <xs:element name="Code" type="xs:int" />
  <xs:element name="Price" type="xs:double" />
</xs:schema>

<xs:schema targetNamespace="http://www.aa.com"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://www.aa.com"
           xmlns:bb="http://www.bb.com"
           elementFormDefault="qualified">
  <xs:import namespace="http://www.bb.com" />
  <xs:redefine schemaLocation="http://www.aa.com">
    <xs:complexType name="Book--type">
      <xs:complexContent>
        <xs:extension base="Book--type">
          <xs:sequence>
            <xs:element ref="bb:Code" />
            <xs:element ref="bb:Price" />
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>
</xs:schema>

答案 1 :(得分:0)

问题在于,即使您在架构B中定义了新类型,示例文档中的根元素也是原始架构A中的Book--type类型。

您需要在文档中使用类型覆盖,如下所示:

<aa:Book xmlns:aa="http://www.aa.com"
         xmlns:bb="http://www.bb.com"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:type="bb:Book--type">
  <aa:Title>Complete Works</aa:Title>
  <aa:Author>Shakespeare</aa:Author>
  <bb:Code>98</bb:Code>
  <bb:Price>31.6</bb:Price>
</aa:Book>