Referencing this: Other post I am trying to do basically the same thing as the OP from this other post; to extend a complexType with my own added attributes, without changing the primary namespace. I tried following the answer reply as closely as possible but am not having success.
Following the last post I created 4 files: 3 xsd's and 1 xml.
original.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://bookshop.com"
targetNamespace="http://bookshop.com"
elementFormDefault="qualified">
<xs:complexType name="Book">
<xs:sequence>
<xs:element name="Author" type="String32"
minOccurs="1" maxOccurs="1" />
<xs:element name="Title" type="String32"
minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
<xs:element name="Book" type="Book"/>
<xs:simpleType name="String32">
<xs:restriction base="xs:string"></xs:restriction>
</xs:simpleType>
</xs:schema>
added.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://custombookshop.com"
xmlns:bs="http://bookshop.com"
targetNamespace="http://custombookshop.com">
<xs:import namespace="http://bookshop.com" schemaLocation="original.xsd"/>
<xs:element name="Publisher" type="bs:String32" />
</xs:schema>
newMainfile.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://bookshop.com"
targetNamespace="http://bookshop.com"
xmlns:cs="http://custombookshop.com">
<xs:import schemaLocation="added.xsd" namespace="http://custombookshop.com"/>
<xs:redefine schemaLocation="original.xsd">
<xs:complexType name="Book">
<xs:complexContent>
<xs:extension base="Book">
<xs:sequence>
<xs:element ref="cs:Publisher" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
</xs:schema>
test.xml
<?xml version="1.0"?>
<Book xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://bookshop.com"
targetNamespace="http://bookshop.com"
xs:schemaLocation="newMainfile.xsd"
xmlns:cs="http://custombookshop.com">
<Author>Frank Herbert</Author>
<Title>Dune</Title>
<cs:Publisher>Ace</cs:Publisher>
</Book>
However, this does not produce something I can validate. After adding the xml and xsd's to the working directory of my c# project running the following code does not work.
var path = @"test.xml";
XmlSchemaSet schema = new XmlSchemaSet();
schema.Add("", "newMainfile.xsd");
XmlReader rd = XmlReader.Create(path);
XDocument doc = XDocument.Load(rd);
doc.Validate(schema, ValidationEventHandler);
An exception occurs with
"System.Xml.Schema.XmlSchemaException: 'The targetNamespace parameter '' should be the same value as the targetNamespace 'http://bookshop.com' of the schema.'"
Substituting the namespace "http://bookshop.com" for the "" in schema.Add("", "newMainfile.xsd"); also does not validate and instead produces error.
System.Xml.Schema.XmlSchemaException: ''SchemaLocation' must successfully resolve if <'redefine'> contains any child other than <'annotation'>.'
Am I missing some sort of vital step? Appreciate your time and responses.
So the issue is that the default resolver of the XmlSchemaSet
class doesn't actually support relative file paths. To get this to work you can either:
<xs:redefine schemaLocation="file://C:/temp/whatever/original.xsd">
orXmlSchema
s through the use of an instance of XmlPreloadedResolver
.using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
// you will need this namespace for the preloaded resolver class
using System.Xml.Resolvers;
void Main()
{
// put all your XSD files to a single folder path
var basePath = @"C:\temp\so76168480";
var path = Path.Combine(basePath, @"test.xml");
// see method definition below
var preloader = PreLoadXmlSchemas(basePath);
XmlSchemaSet schemaSet = new XmlSchemaSet() {
XmlResolver = preloader
};
schemaSet.Add("http://bookshop.com", Path.Combine(basePath, "newMainfile.xsd"));
XmlReader rd = XmlReader.Create(path);
XDocument doc = XDocument.Load(rd);
doc.Validate(schemaSet, (i, e) => {
// should be ok
});
}
public static XmlPreloadedResolver PreLoadXmlSchemas(string directoryPath)
{
if (directoryPath == null) throw new ArgumentNullException(nameof(directoryPath));
var directoryInfo = new DirectoryInfo(directoryPath);
FileInfo[] additionalXsds = directoryInfo.GetFiles("*.xsd");
var xmlPreloadedResolver = new XmlPreloadedResolver();
foreach (FileInfo xsd in additionalXsds)
{
xmlPreloadedResolver.Add(new Uri($"file://{xsd.FullName}"), File.OpenRead(xsd.FullName));
}
return xmlPreloadedResolver;
}
The XmlPreloadedResolver is available on .NET Framework, .NET Core and .NET 5+ so it should be immediately available to use.