XSD:如何重新定义基本模式的标签

Posted

技术标签:

【中文标题】XSD:如何重新定义基本模式的标签【英文标题】:XSD: how to redefine tags of base schema 【发布时间】:2021-07-05 09:23:15 【问题描述】:

为了在 C# 应用程序中验证不同的 XML 文件,我必须处理多个 XML 模式。所有这些 XML 模式都共享一些基本元素,如果不用每次都重新定义它们,将它们放在一个共同的地方就好了。

我的想法是创建一个 BaseSchema.xsd 文件来定义这些通用元素,并创建一个 SpecificSchema#.xsd 文件来定义特定的案例相关元素。在这些SpecificSchema#.xsd 架构中,我需要使用基本架构的一些元素,还要重新定义根标记。

这是我需要的一个例子:

BaseSchema.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="BaseSchema"
           targetNamespace="http://company.com/myBaseSchema"
           elementFormDefault="qualified"
           xmlns="http://company.com/myBaseSchema"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  
  <xs:element name="myRootTag" type="myRootTag" />

  <xs:complexType name="myRootTag">
    <!-- some content -->
  </xs:complexType>

  <xs:complexType name="someCommonTag">
    <!-- some content -->
  </xs:complexType>
</xs:schema>

SpecificSchema1.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="SpecificSchema1"
           targetNamespace="http://company.com/myBaseSchema"
           elementFormDefault="qualified"
           xmlns="http://company.com/myBaseSchema"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:include schemaLocation="BaseSchema.xsd"/>
  
  <xs:redefine schemaLocation="BaseSchema.xsd">
    <xs:complexType name="myRootTag">
      <xs:complexContent>
        <xs:extension base="myRootTag">
          <!-- some content -->
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>

  <xs:complexType name="someCustomTag">
    <xs:sequence>
      <!-- some content -->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

SpecificSchema2.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="SpecificSchema2"
           targetNamespace="http://company.com/myBaseSchema"
           elementFormDefault="qualified"
           xmlns="http://company.com/myBaseSchema"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:include schemaLocation="BaseSchema.xsd"/>
  
  <xs:redefine schemaLocation="BaseSchema.xsd">
    <xs:complexType name="myRootTag">
      <xs:complexContent>
        <xs:extension base="myRootTag">
          <!-- some other content different from SpecificSchema1.xsd -->
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>

  <xs:complexType name="someOtherCustomTag">
    <xs:sequence>
      <!-- some content -->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

我需要验证的 XML 文件是这样的(它们永远不会引用BaseSchema.xsd):

<?xml version="1.0" encoding="utf-16" ?>
<myRootTag xmlns="http://company.com/myBaseSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://company.com/myBaseSchema SpecificSchema1.xsd">
  <!-- some content -->
</myRootTag>

显然这似乎有效(所有模式都在同一个目录中,并且它们都引用相同的 targetNamespace),但是当我尝试将所有模式加载到 System.Xml.Schema.XmlSchemaSet 中时,它会引发此异常:

'SchemaLocation' must successfully resolve if <redefine> contains any child other than <annotation>.

我还尝试在覆盖架构中引用 BaseSchema.xsd 的完整路径,但没有成功。

这是我用于模式加载的 C# 代码:

private XmlSchemaSet LoadSchemas()

    var schemaSet = new XmlSchemaSet();

    foreach (var schemaPath in Directory.GetFiles(schemasDirectory))
    
        var schema = LoadSchema(schemaPath);
        schemaSet.Add(schema);
    

    return schemaSet;


private XmlSchema LoadSchema(string uri)

    using (var reader = XmlReader.Create(uri))
    
        return XmlSchema.Read(reader, null);
    

我做错了什么?

谢谢。

编辑:我还尝试仅在 SpecificSchema#.xsd 模式中定义根标签,而不是在基本模式中,因此不需要重新定义,但在创建阅读器来验证我的 XML:

The global element 'http://company.com/myBaseSchema:myRootTag' has already been declared.

【问题讨论】:

您可能需要包含语句:w3schools.com/xml/el_include.asp @jdweng 我已经有&lt;xs:include schemaLocation="BaseSchema.xsd"/&gt;。只写我的 XSD 基本文件的名称可以吗? (所有模式都在同一个文件夹中) 通常您将包含放在根架构中以包含子架构。您的 c# 代码将引用根架构,并且将使用根中的包含找到子架构。 @jdweng 所以在我的BaseSchema.xsd 中,我应该将我的派生模式的包含放在SpecificSchema#.xsd 中,然后将重新定义留在SpecificSchemas#.xsd 中?它似乎不起作用,当我加载 SpecificSchema#.xsd 架构时,它说“'重新定义'元素不能出现在这个位置”。 架构由组织生成,用于标准化现实行业等数据传输,并且通常在主架构中包含用户定义的类型。假设用户编辑主模式以添加新类型来代替用户定义的类型。将 Include 语句添加到 Main Schema。然后为用户类型创建一个新模式。这最大限度地减少了用户在发布新版本架构时需要进行的更改。 【参考方案1】:

我仅在架构集中使用System.Xml.XmlUrlResolver 修复了'SchemaLocation' must successfully resolve if &lt;redefine&gt; contains any child other than &lt;annotation&gt;. 问题,以这种方式更改了我的加载逻辑:

private XmlSchemaSet LoadSchemas()

    var schemaSet = new XmlSchemaSet();
    schemaSet.XmlResolver = new System.Xml.XmlUrlResolver();    // this was my missing line

    foreach (var schemaPath in Directory.GetFiles(schemasDirectory))
    
        var schema = LoadSchema(schemaPath);
        schemaSet.Add(schema);
    

    return schemaSet;


private XmlSchema LoadSchema(string uri)

    using (var reader = XmlReader.Create(uri))
    
        return XmlSchema.Read(reader, null);
    

但是将所有架构(基本架构和所有 SpecificSchema#.xsd 架构)一起加载给了我另一个错误:

The complexType 'http://company.com/BaseSchema:myRootTag' has already been declared.

因此,由于我确切知道必须使用哪个SpecificSchema#.xsd,所以我再次更改了加载逻辑,只加载需要的那个:

private static XmlSchemaSet LoadSchemaSet()

    var schemaSet = new XmlSchemaSet();
    schemaSet.XmlResolver = new System.Xml.XmlUrlResolver();

    var schemaPath = schemasDirectory + "\\SpecifiSchema1.xsd";
    var schema = LoadSchema(schemaPath);
    schemaSet.Add(schema);

    return schemaSet;

我还删除了SpecificSchema#.xsd 模式中的&lt;xs:include&gt; 标记,但在这种情况下它没有任何区别(&lt;xs:redefine&gt;BaseSchema.xsd 元素的所有其他用法在有和没有它的情况下都有效)。

【讨论】:

以上是关于XSD:如何重新定义基本模式的标签的主要内容,如果未能解决你的问题,请参考以下文章

如何定义XSD并在XML中使用XSD

使用Notepad ++ XML Tools创建XSD

XML的验证模式DTD与XSD的区别

聊聊自定义SPI如何使用自定义标签注入到spring容器中

xsd 后缀文件用啥软件打开

如何在基于 Docbook 标签的 XSD 中包含 MathML 标签?