EDIT See my solution below /EDIT
I have a Visual Studio solution with two projects.
- Project 1 (call it ReferencedProject) contains an XML schema file (ReferencedSchema.xsd).
- Project 2 (call it MainProject) contains ReferencedProject as a reference. MainProject also has a schema file (MainSchema.xsd).
MainSchema.xsd contains the following code:
<?xml version="1.0"?>
<xs:schema
xmlns="main"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="main"
targetNamespace="main"
elementFormDefault="qualified">
<xs:include schemaLocation="ReferencedSchema.xsd" />
...
</xs:schema>
Because ReferencedSchema.xsd is not in the same folder (it's not even in the same project), I get an error saying "ReferencedSchema.xsd could not be resolved." Makes sense.
If I edit the xs:include element to this...
<xs:include schemaLocation="../../ReferencedProject/Data/ReferencedSchema.xsd" />
...the error goes away. However, notice that I've provided a relative path to the schema that will only work within my solution's folder hierarchy. That's great when I'm viewing the schema in the editor but not so great when I compile my project. If I look in my "bin" folder after compiling, the folder hierarchy is completely different (the two xsd files actually end up in the same folder).
I tried to get around this using Visual Studio's "Add Existing Item As Link" feature, putting a shortcut to the ReferencedSchema.xsd file in the same folder as my main schema file, but that didn't work. The XSD validator apparently isn't capable of pretending the link is the actual file.
So, my problem is that there doesn't seem to be any uri I can provide for schemaLocation that will be valid in both situations (within the solution explorer and during runtime). Does anyone have any suggestions?
Thanks!
EDIT
I decided to go with this:
<xs:include schemaLocation="../../ReferencedProject/Data/ReferencedSchema.xsd" />
This is correct as long as I'm viewing things within Visual Studio, incorrect when running my code.
To make it work at runtime as well, I dynamically replace the schemaLocation with the correct relative reference as follows:
public class UriReplacingXmlValidator
{
public virtual XDocument Validate(
string dataFolderName,
string baseDataFolderName,
string xmlFileName,
string schemaFileName,
string baseSchemaFileName)
{
string rootFolderPath = Environment.CurrentDirectory + Path.DirectorySeparatorChar;
string dataFolderPath = rootFolderPath + Path.DirectorySeparatorChar + dataFolderName;
string baseDataFolderPath = rootFolderPath + Path.DirectorySeparatorChar + baseDataFolderName;
string xmlPath = dataFolderPath + Path.DirectorySeparatorChar + xmlFileName;
string schemaPath = dataFolderName + Path.DirectorySeparatorChar + schemaFileName;
string baseSchemaPath = baseDataFolderName + Path.DirectorySeparatorChar + baseSchemaFileName;
XDocument xmlDocument = XDocument.Load(xmlPath);
XDocument schemaDocument = XDocument.Load(schemaPath);
ResetBaseSchemaLocation(schemaDocument, baseSchemaPath);
XmlValidator validator = new XmlValidator();
bool isValid = validator.Validate(xmlDocument, schemaDocument);
if (isValid)
return xmlDocument;
else
return null;
}
protected virtual void ResetBaseSchemaLocation(XDocument schemaDocument, string baseSchemaPath)
{
XNamespace ns = "http://www.w3.org/2001/XMLSchema";
XAttribute attribute = schemaDocument.Element(ns + "schema").Element(ns + "redefine").Attribute("schemaLocation");
attribute.Value = baseSchemaPath;
}
I went with this solution because everything now works whether I'm viewing my XML and XSD files in Visual Studio or running/debugging my app.