xsd:在Embedded Resource XSD中导入

时间:2011-03-16 21:14:05

标签: c# .net visual-studio-2010 xsd embedded-resource

我有一个类库项目,它在我的解决方案中包含其他项目之间的一些共享代码。其中一个共享代码涉及针对XSD文件的运行XML验证。 XSD的名称作为参数传递给方法,然后使用Assembly.GetFile()加载。

问题是XSD文件导入另外两个XSD 。我已经将所有三个作为资源加载到我的类库中但是从我读过的xsd:import不起作用。是否有其他方法可以在我的类库项目中使用这些XSD而不会破坏xsd:import语句?

修改 - 更新

我在下面实施了Alexander's suggestion,但正如我在评论中所述,每当GetEntity()'XSD调用xs:import时,ofObjectToReturnnull。这导致xs:import'd类型的第一个实例抛出异常“未定义的类型”。

为了解决此问题,无论GetEntity()的值如何,我都将GetManifestResourceStream()更改为ofObjectToReturn。现在,这似乎适用于xs:import语句的第一级,但其中一个原始xs:import XSD中的辅助xs:import无效。我已确认正在为此辅助GetEntity()调用xs:import,但我收到此辅助XSD中定义的类型的“未定义类型”异常。

  • TopLevel.xsd - 类型解析
    • FirstLevelImport1.xsd - 类型解析
    • FirstLevelImport2.xsd - 类型解析
      • SecondLevelImport1.xsd - “type not defined”此XSD中定义的类型抛出异常

XmlReader.Create()传递定义架构验证的XmlReaderSettings期间抛出“未定义类型”异常。

2 个答案:

答案 0 :(得分:5)

要解析由xsd:importxsd:include添加的文件,您可以使用自定义 XmlResolver 。您可以在下面找到 ResourceXmlResolver 的示例。它假设程序集的名称是“ AYez.EmbeddedXsdTests ”。

using System.Xml;
using System.Xml.Schema;
using NUnit.Framework;

namespace AYez.EmbeddedXsdTests
{
    [TestFixture]
    public class EmbeddedXsdTests
    {
        [Test]
        public void SomeEntryPoint()
        {
            var schemaSet = new XmlSchemaSet {XmlResolver = new ResourceXmlResolver()};
            schemaSet.Add("rrn:org.xcbl:schemas/xcbl/v4_0/financial/v1_0/financial.xsd", @"Invoice.xsd");
            schemaSet.Compile();

            var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = schemaSet };

            settings.ValidationEventHandler += delegate(object o, ValidationEventArgs e)
            {
                switch (e.Severity)
                {
                    case XmlSeverityType.Error:
                        Console.Write("Error: {0}", e.Message);
                        break;
                    case XmlSeverityType.Warning:
                        Console.Write("Warning: {0}", e.Message);
                        break;
                }
            };
            var xmlReader = XmlReader.Create(@"d:\temp\Invoice.xml", settings);
            while (xmlReader.Read()) { /*TODO: Nothing*/} // Validation is performed while reading

        }
    }

    public class ResourceXmlResolver: XmlResolver
    {
        /// <summary>
        /// When overridden in a derived class, maps a URI to an object containing the actual resource.
        /// </summary>
        /// <returns>
        /// A System.IO.Stream object or null if a type other than stream is specified.
        /// </returns>
        /// <param name="absoluteUri">The URI returned from <see cref="M:System.Xml.XmlResolver.ResolveUri(System.Uri,System.String)"/>. </param><param name="role">The current version does not use this parameter when resolving URIs. This is provided for future extensibility purposes. For example, this can be mapped to the xlink:role and used as an implementation specific argument in other scenarios. </param><param name="ofObjectToReturn">The type of object to return. The current version only returns System.IO.Stream objects. </param><exception cref="T:System.Xml.XmlException"><paramref name="ofObjectToReturn"/> is not a Stream type. </exception><exception cref="T:System.UriFormatException">The specified URI is not an absolute URI. </exception><exception cref="T:System.ArgumentNullException"><paramref name="absoluteUri"/> is null. </exception><exception cref="T:System.Exception">There is a runtime error (for example, an interrupted server connection). </exception>
        public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
        {   
                // If ofObjectToReturn is null, then any of the following types can be returned for correct processing:
                // Stream, TextReader, XmlReader or descendants of XmlSchema
                var result =  this.GetType().Assembly.GetManifestResourceStream(string.Format("AYez.EmbeddedXsdTests.{0}",
                                                                                             Path.GetFileName(absoluteUri.ToString())));                
                // set a conditional breakpoint "result==null" here
                return result;
        }

        /// <summary>
        /// When overridden in a derived class, sets the credentials used to authenticate Web requests.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Net.ICredentials"/> object. If this property is not set, the value defaults to null; that is, the XmlResolver has no user credentials.
        /// </returns>
        public override ICredentials Credentials
        {
            set { throw new NotImplementedException(); }
        }
    }
}

答案 1 :(得分:2)

如果我们首先将xsd文件读入字符串变量,则可以解决问题。

e.g。

var stream =assembly.GetManifestResourceStream("Namespace.child.xsd");

现在使用流阅读器将其读入字符串

e.g。

string childXSD=new StreamReader(stream).ReadToEnd();

相似得到字符串ParentXSD 然后使用

var xmlReader=XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(childXSD)));
schemaCollection.Add(null,xmlReader);
var xmlReader=XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(parentXSD)));
schemaCollection.Add(null,xmlReader);

我认为孩子对父母的顺序很重要,因为我们将儿童XSD引用为父母。