当我的所有 .XSD 都存储为资源时,如何解析 .XSD 的 schemaLocation 属性? [英] How can I resolve the schemaLocation attribute of an .XSD when all of my .XSD's are stored as resources?

查看:21
本文介绍了当我的所有 .XSD 都存储为资源时,如何解析 .XSD 的 schemaLocation 属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个项目,我需要根据嵌套的 XSD 生成 XML 文件.例如ORDER 有对 PERSON 的引用,PERSON 有对 ADDRESS 的引用,等等.

I am working on a project where I need to generate XML files based on nested XSD's. e.g. ORDER has a reference to PERSON, PERSON has a reference to ADDRESS, etc.

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

I am creating an `XmlReaderSettings' instance to validate the XSD's, as well as validate the XML after it is generated.

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

I have added the XSD's as Resources to my assembly. I then create an XmlSchema instance for each resource, from lowest to highest, and add it to the XmlReaderSettings.Schemas collection.

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

However, this fails attempting to add a schema that references another schema. I get an XmlSchemaException: "For element declaration, either the name or the ref attribute must be present."

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

I have included sample XSD's and source code below:

ADDRESS.xsd - 由 PERSON.xsd 引用

ADDRESS.xsd - referenced by 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

Sample Code - Load and validate XSD's

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 集合时.

I am not sure if this has anything to do with the ValidationFlags, but I tried removing XmlSchemaValidationFlags.ProcessSchemaLocation and still received the same error. I have also tried passing SchemaValidationEventHandler to the XmlSchema.Read method (instead of null in sample code), and the schema seems to be created OK, but it still throws the exception when attemtping to add it to the XmlReaderSettings.Schemas collection.

编辑 - 2011.11.03

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

I resolved this issue (pun intended) by creating my own XmlUrlResolver descendent called XmlResourceResolver, based on the XmlResolver class example in accepted answer below.

推荐答案

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

To get rid of the error, change type="Addresses" to name="Addresses" in your PERSON.xsd file.

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

It is better to go with the code below to get schemas compiled. The important things are to make sure you establish a base uri (since you're reading from a stream), to use an XmlSchemaSet instead, and a custom resolver (to read files as embedded resources).

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

这篇关于当我的所有 .XSD 都存储为资源时,如何解析 .XSD 的 schemaLocation 属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆