You can use the XmlSchema.Includes to link them together. Then, you just need to add the main schema to the schema set:
var includeSchema = XmlSchema.Read(XmlReader.Create(...), null);
var mainSchema = XmlSchema.Read(XmlReader.Create(...), null);
var include = new XmlSchemaInclude();
include.Schema = includeSchema;
mainSchema.Includes.Add(include);
var schemaSet = new XmlSchemaSet();
schemaSet.Add(mainSchema);
schemaSet.Compile();
Try this :D
public static XmlSchema LoadSchema(string pathname)
{
XmlSchema s = null;
XmlValidationHandler h = new XmlValidationHandler();
using (XmlReader r = XmlReader.Create(new FileStream(pathname, FileMode.Open)))
{
s = XmlSchema.Read(r, new ValidationEventHandler(h.HandleValidationEvent));
}
if (h.Errors.Count > 0)
{
throw new Exception(string.Format("There were {1} errors reading the XSD at {0}. The first is: {2}.", pathname, h.Errors.Count, h.Errors[0]));
}
return s;
}
public static XmlSchema LoadSchemaAndResolveIncludes(string pathname)
{
FileInfo f = new FileInfo(pathname);
XmlSchema s = LoadSchema(f.FullName);
foreach(XmlSchemaInclude i in s.Includes)
{
XmlSchema si = LoadSchema(f.Directory.FullName + @"\" + i.SchemaLocation);
si.TargetNamespace = s.TargetNamespace;
i.Schema = si;
}
return s;
}
public static List<ValidationEventArgs> Validate(string pathnameDocument, string pathnameSchema)
{
XmlSchema s = LoadSchemaAndResolveIncludes(pathnameSchema);
XmlValidationHandler h = new XmlValidationHandler();
XmlDocument x = new XmlDocument();
x.Load(pathnameDocument);
x.Schemas.Add(s);
s.Compile(new ValidationEventHandler(h.HandleValidationEvent));
x.Validate(new ValidationEventHandler(h.HandleValidationEvent));
return h.Errors;
}
Note in particular the si.TargetNamespace = s.TargetNamespace;
.
Obviously, this assumes that the includes are specified as file paths relative to the schema into which they are included.
The problem is with the way the schema is opened for reading on the line:
XmlReader.Create(new FileStream(sd, FileMode.Open)
I had to write my own XmlResolver
before I could see how the paths to the include files were being resolved: it was from the directory of the executable and not from the directory of the parent schema. The problem is that the parent schema was not getting its BaseURI set. Here's how the schema must be opened:
XmlReader.Create(new FileStream(pathname, FileMode.Open, FileAccess.Read),null, pathname)
Here is the method I wrote to handle xsd validation. Hope this helps some one.
/// <summary>
/// Ensure all xsd imported xsd documented are in same folder as master xsd
/// </summary>
public XsdXmlValidatorResult Validate(string xmlPath, string xsdPath, string xsdNameSpace)
{
var result = new XsdXmlValidatorResult();
var readerSettings = new XmlReaderSettings {ValidationType = ValidationType.Schema};
readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
readerSettings.Schemas.Add(null, xsdPath);
readerSettings.ValidationEventHandler += (sender, args) =>
{
switch (args.Severity)
{
case XmlSeverityType.Warning:
result.Warnings.Add(args.Message);
break;
case XmlSeverityType.Error:
result.IsValid = false;
result.Warnings.Add(args.Message);
break;
}
};
var reader = XmlReader.Create(xmlPath, readerSettings);
while (reader.Read()) { }
return result;
}