【问题标题】:xsd:import inside an Embedded Resource XSDxsd:在嵌入式资源 XSD 中导入
【发布时间】:2011-07-16 22:53:58
【问题描述】:

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

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

编辑 - 更新

我在下面实现了Alexander's suggestion,但正如我在评论中所说,每当GetEntity() 被称为xs:import'd XSD 时,ofObjectToReturn 就是null。这导致xs:import'd 类型的第一个实例引发异常“类型未定义”。

为了解决这个问题,我将GetEntity() 更改为返回GetManifestResourceStream(),而不考虑ofObjectToReturn 的值。这现在似乎适用于第一级xs:import 语句,但在原始xs:import XSD 中的一个二级xs:import 不起作用。我已确认此辅助 xs:import 正在调用 GetEntity(),但我收到此辅助 XSD 中定义的类型的“类型未定义”异常。

  • TopLevel.xsd - 类型解析得很好
    • FirstLevelImport1.xsd - 类型解析很好
    • FirstLevelImport2.xsd - 类型解析得很好
      • SecondLevelImport1.xsd - 为此 XSD 中定义的类型抛出“未定义类型”异常

XmlReader.Create() 期间抛出“类型未定义”异常,该异常通过定义架构验证的XmlReaderSettings

【问题讨论】:

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


    【解决方案1】:

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

    例如

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

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

    例如

    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 引用到父级中。

    【讨论】:

      【解决方案2】:

      要解析由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(); }
              }
          }
      }
      

      【讨论】:

      • 每当GetEntity() 被称为xsl:import'd 架构时,ofObjectToReturn 就是null,因此我收到一个异常,指出未定义导入的类型。
      • 你是对的。只需删除该特定场景中的 if 语句即可。通常我们应该检查ofObjectToReturn参数并返回一个相同类型的对象。
      • ...但是,如果是null,则应返回以下之一:StreamTextReaderXmlReaderXmlSchema 的后代。我是在查看 .NET 框架的 System.Xml 的源代码后发现的。 :)
      • 刚刚注意到您的更新: 我遇到了同样的例外情况,但并非所有 xsd 文件都作为资源包含在程序集中。当您在GetEntity 中将条件断点设置到return 时,您可以简单地检查它
      猜你喜欢
      • 1970-01-01
      • 2012-04-01
      • 2019-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 2012-08-21
      相关资源
      最近更新 更多