代码之家  ›  专栏  ›  技术社区  ›  Nathan Baulch

从现有架构扩展复杂类型

  •  2
  • Nathan Baulch  · 技术社区  · 14 年前

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

    例如,假设我想添加 Code Price 将元素添加到现有 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 回复  |  直到 14 年前
        1
  •  1
  •   Nathan Baulch    14 年前

    事实证明 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>
    
        2
  •  0
  •   xcut    14 年前

    问题是,即使在模式B中定义了新类型,示例文档中的根元素的类型仍然是 Book--type 从原始模式A。

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

    <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>