Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify an XSD schemaLocation attribute in VS when the referenced schema file is in a different project/assembly?

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.

like image 550
devuxer Avatar asked Jul 01 '09 23:07

devuxer


People also ask

What is schemaLocation in XSD?

The xsi:schemaLocation attribute locates schemas for elements and attributes that are in a specified namespace. Its value is a namespace URI followed by a relative or absolute URL where the schema for that namespace can be found. It is most commonly attached to the root element but can appear further down the tree.

How can we define within an XSD?

Defining XML ElementsEach element definition within the XSD must have a 'name' property, which is the tag name that will appear in the XML document. The 'type' property provides the description of what type of data can be contained within the element when it appears in the XML document.

Which attribute is used to reference an XML Schema in an XML?

The 'noNamespaceSchemaLocation' attribute is used to reference XML Schema(s) that are not defined in a target-namespace.


2 Answers

XSD only supports URI locations, not path location. This means that file:///C:/path/to/VS/Projects/ReferencedProject/Data/ReferencedSchema.xsd is valid, but not ../../ReferencedProject/Data/ReferencedSchema.xsd.

like image 102
T0xicCode Avatar answered Oct 16 '22 16:10

T0xicCode


Disclaimer: I don't know a lot about XML schema. Anyway, I ran into the same problem as you.

Using xs:import rather than xs:include seemed to solve my problem in VS designer.

First schema:

<xs:schema id="schema1"
    targetNamespace="http://tempuri.org/schema1.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/schema1.xsd"
    xmlns:mstns="http://tempuri.org/schema1.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="MyType" nillable="true"/>
<xs:complexType name="MyType">
  <xs:all>
    <xs:element name="Value1" type="xs:double"/>
    <xs:element name="Value2" type="xs:double"/>
  </xs:all>
</xs:complexType>

</xs:schema>

Second schema:

<xs:schema id="schema2"
    targetNamespace="http://tempuri.org/schema2.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/schema2.xsd"
    xmlns:mstns="http://tempuri.org/schema2.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:schema1="http://tempuri.org/schema1.xsd"
>
  <xs:import namespace="http://tempuri.org/schema1.xsd"/>

  <xs:element name="MySecondType" nillable="true"/>
  <xs:complexType name=MySecondType>
    <xs:element name="Value" type="schema1:MyType/>
  </xs:complexType>
</xs:schema>

When editing XML schema in Visual Studio, you can see which schema's are active using menu item XML --> Schemas.

like image 20
Menno Deij - van Rijswijk Avatar answered Oct 16 '22 16:10

Menno Deij - van Rijswijk