Xsd: import inside XSD embedded resource

I have a class library project that contains some common code between other projects in my solution. One of these shared codes involves performing XML validation against an XSD file. The XSD name is passed as a parameter to the method and then loaded using Assembly.GetFile() .

The problem is that the XSD file imports two other XSDs . I have loaded all three as resources into my class library, but from what I read, xsd: import will not work. Is there an alternative approach for making these XSDs available in my Library Library project without breaking xsd:import instructions?

Change - Update

I have implemented Alexander's suggestion below, but as I said in my comment, whenever GetEntity() is called for xs:import 'd XSD, ofObjectToReturn is null . This led to the first instance of type xs:import 'd throwing an exception of "type not defined".

To solve this problem, I modified GetEntity() to return GetManifestResourceStream() regardless of the value ofObjectToReturn . This seems to work for the first level of xs:import statements, but the secondary xs:import inside one of the original xs:import does not work. I have confirmed that GetEntity() is called for this secondary xs:import , but I get a type exception not defined for the type defined in this secondary XSD.

  • TopLevel.xsd - types
    • FirstLevelImport1.xsd - types allow small
    • FirstLevelImport2.xsd - types
      • SecondLevelImport1.xsd - type exception not defined for the type defined in this XSD

In XmlReader.Create() an "undefined" exception is thrown, which is passed to XmlReaderSettings , which determines the validation of the schema.

+4
source share
2 answers

To allow files added with either xsd:import or xsd:include , you can use a custom XmlResolver . The following is an example ResourceXmlResolver . He assumes the assembly name is "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(); } } } } 
+5
source

The problem can be fixed if we first read the xsd files in a string variable.

eg.

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

now use Stream Reader to read this in line

eg.

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

similary get string ParentXSD Then use

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

I think that the sequence of children for the parent is important as we refer to the child XSD on the parent.

+2
source

Source: https://habr.com/ru/post/1344008/


All Articles