【问题标题】:How can I resolve the schemaLocation attribute of an .XSD when all of my .XSD's are stored as resources?当我的所有 .XSD 都存储为资源时,如何解析 .XSD 的 schemaLocation 属性?
【发布时间】:2011-11-02 14:46:52
【问题描述】:

我正在开发一个需要基于嵌套 XSD 生成 XML 文件的项目。例如ORDER 引用了 PERSON,PERSON 引用了 ADDRESS,等等。

我正在创建一个“XmlReaderSettings”实例来验证 XSD,并在生成 XML 后对其进行验证。

我已将 XSD 作为资源添加到我的程序集中。然后我为每个资源创建一个XmlSchema 实例,从最低到最高,并将其添加到XmlReaderSettings.Schemas 集合中。

但是,尝试添加引用另一个架构的架构时会失败。我收到 XmlSchemaException:“对于元素声明,必须存在名称或 ref 属性。”

我在下面包含了示例 XSD 和源代码:

ADDRESS.xsd - 由 PERSON.xsd 引用

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="ADDRESS.xsd" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ADDRESS" >
    <xs:complexType>
      <xs:sequence>
        <xs:element name="ADDRESS1" type="xs:string"/>
        <xs:element name="ADDRESS2" type="xs:string"/>
        <xs:element name="CITY" type="xs:string"/>
        <xs:element name="STATE" type="xs:string"/>
        <xs:element name="ZIP" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

PERSON.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="PERSON.xsd" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:include schemaLocation="ADDRESS.xsd"/>
  <xs:element name="PERSON" >
    <xs:complexType>
      <xs:sequence>
        <xs:element name="L_NAME" type="xs:string"/>
        <xs:element name="F_NAME" type="xs:string"/>
        <xs:element name="Addresses">
          <xs:complexType>
            <xs:sequence>
              <xs:element ref="ADDRESS" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

示例代码 - 加载和验证 XSD

using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using SchemaTest.Properties;

namespace SchemaTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // create validation settings instance
            var xmlReaderSettings = new XmlReaderSettings
            {
                ValidationType = ValidationType.Schema,
                ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema |
                                  XmlSchemaValidationFlags.ProcessSchemaLocation |
                                  XmlSchemaValidationFlags.ReportValidationWarnings
            };

            xmlReaderSettings.ValidationEventHandler += SchemaValidationEventHandler;

            // added XmlResourceResolver, per the accepted answer below
            xMLReaderSettings.Schemas.XmlResolver = new XmlResourceResolver();

            // load schemas into validation settings instance
            LoadSchema(xmlReaderSettings, Resources.PERSON);

            // validate schemas
            xmlReaderSettings.Schemas.Compile();

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        private static void LoadSchema(XmlReaderSettings xmlReaderSettings, string schemaString)
        {
            using (var schemaStream = new MemoryStream(Encoding.Default.GetBytes(schemaString)))
            {
                var schema = XmlSchema.Read(schemaStream, null);

                try
                {
                    xmlReaderSettings.Schemas.Add(schema);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("EXCEPTION: {0}", ex.Message);
                }
            }
        }

        private static void SchemaValidationEventHandler(object sender, ValidationEventArgs e)
        {
            Console.WriteLine("{0}: {1}", e.Severity, e.Message);
        }
    }
}

我不确定这是否与ValidationFlags 有关,但我尝试删除XmlSchemaValidationFlags.ProcessSchemaLocation 并仍然收到相同的错误。我还尝试将SchemaValidationEventHandler 传递给XmlSchema.Read 方法(而不是示例代码中的null),并且架构似乎创建得很好,但是在尝试将其添加到XmlReaderSettings.Schemas 集合时仍然抛出异常。

编辑 - 2011.11.03

我根据下面接受的答案中的XmlResolver 类示例创建了自己的XmlUrlResolver 后代XmlResourceResolver,从而解决了这个问题(双关语)。

【问题讨论】:

    标签: c# xml .net-4.0 xsd


    【解决方案1】:

    要消除错误,请将 PERSON.xsd 文件中的 type="Addresses" 更改为 name="Addresses"。

    最好使用下面的代码来编译模式。重要的是确保您建立一个基本 uri(因为您正在从流中读取)、使用 XmlSchemaSet 和自定义解析器(将文件作为嵌入式资源读取)。

    using System;
    using System.IO;
    using System.Text;
    using System.Xml;
    using System.Xml.Schema;
    
    namespace ConsoleApplication3
    {
        class Program
        {
            class XmlResolver : XmlUrlResolver
            {
                internal const string BaseUri = "schema://";
    
                public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
                {
                    if (absoluteUri.Scheme == "schema")
                    {
                        switch (absoluteUri.LocalPath)
                        {
                            case "/ADDRESS.xsd":
                                return new MemoryStream(Encoding.UTF8.GetBytes(Resource.ADDRESS));
                            case "/PERSON.xsd":
                                return new MemoryStream(Encoding.UTF8.GetBytes(Resource.PERSON));
                        }
                    }
                    return base.GetEntity(absoluteUri, role, ofObjectToReturn);
                }
            }
    
            static void Main(string[] args)
            {
                using (XmlReader reader = XmlReader.Create(new StringReader(Resource.PERSON), new XmlReaderSettings(), XmlResolver.BaseUri))
                {
                    XmlSchemaSet xset = RetrieveSchemaSet(reader);
                    Console.WriteLine(xset.IsCompiled);
                }
            }
    
            private static XmlSchemaSet RetrieveSchemaSet(XmlReader reader)
            {
                XmlSchemaSet xset = new XmlSchemaSet() { XmlResolver = new XmlResolver() };
                xset.Add(XmlSchema.Read(reader, null));
                xset.Compile();
                return xset;
            }
        }
    }
    

    【讨论】:

    • XmlResolver 成功了。我使用您的示例创建了我自己的自定义解析器,并重构了我的代码以将解析器分配给我的 xmlReaderSettings.Schemas 架构集。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 2020-08-12
    • 1970-01-01
    相关资源
    最近更新 更多