How to specify an XSD schemaLocation attribute in

2020-07-07 11:35发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

Use a public URL or a common network share put both files at that location.