Compiling two embedded XSDs: error "Cannot resolve 'schemaLocation' attribute [duplicate] - c#

This question already has an answer here:
How can I resolve the schemaLocation attribute of an .XSD when all of my .XSD's are stored as resources?
(1 answer)
Closed 7 years ago.
I am trying to compile 2 embedded XSDs into a single XSD file but I am getting the error "cannot resolve 'schemaLocation' attribute". I am unsure how to fix this but am guessing its the namespaces some how.
Schema1.xsd does an xsd:include to Schema2.xsd
Schem1.xsd (embedded resource) (simplified)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.somedomain.co.uk/application" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.somedomain.co.uk/application" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:include schemaLocation="Schema2.xsd"/>
</xsd:schema>
Schema2.xsd (embedded resource) (simplified)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.somedomain.co.uk/application" targetNamespace="http://www.somedomain.co.uk/application" elementFormDefault="qualified" attributeFormDefault="unqualified" id="someId">
</xsd:schema>
Code
using System;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
namespace Example
{
class Program
{
public static void Main()
{
XmlSchema schema1 = null;
using (XmlTextReader xtr = new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Example.Schema1.xsd")))
{
schema1 = XmlSchema.Read(xtr, new ValidationEventHandler(XSDValidationEventHandler));
xtr.Close();
}
XmlSchema schema2 = null;
using (XmlTextReader xtr = new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Example.Schema2.xsd")))
{
schema2 = XmlSchema.Read(xtr, new ValidationEventHandler(XSDValidationEventHandler));
xtr.Close();
}
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.ValidationEventHandler += new ValidationEventHandler(XSDValidationEventHandler);
schemaSet.Add(schema1); //error writes out to console here
schemaSet.Add(schema2);
schemaSet.Compile();
XmlSchema compiledSchema = null;
foreach (XmlSchema schema in schemaSet.Schemas())
{
compiledSchema = schema;
}
Console.WriteLine("Finished");
Console.ReadKey();
}
public static void XSDValidationEventHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine(args.Message);
}
}
}
NOTE: I am not allowed to change the XSDs content or change them to not being an embedded resource.
Any questions feel free to ask
Thanks
Kyle

When you're using embedded files, the default XmlTextReader is not able to find referenced files. After creating the XmlTextReader, you must supply it with a XmlResolver that is aware of handling embedded files.
using (XmlTextReader xtr = new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Example.Schema1.xsd")))
{
xtr.XmlResolver = new EmbeddedResourceResolver();
schema1 = XmlSchema.Read(xtr, new ValidationEventHandler(XSDValidationEventHandler));
xtr.Close();
}
The 'EmbeddedResourceResolver' is not an existing Framework class, but can be created by yourself. You can find a reference implementation below.
using System;
using System.Xml;
using System.Reflection;
using System.IO;
namespace MyApp
{
public class EmbeddedResourceResolver : XmlUrlResolver
{
public override object GetEntity(Uri absoluteUri,
string role, Type ofObjectToReturn)
{
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetManifestResourceStream("the.path.to.your.resource");
}
}
}
Because you're not allowed to change the XML, your implementation depends on where the embedded resources are put in your project structure.
You can find more info on the XmlResolver here
My final code
NOTE: For reference both my embedded XSDs were located at the root of my project
using System;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
namespace Example
{
public class EmbeddedResourceResolver : XmlUrlResolver
{
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetManifestResourceStream("Example.Schema2.xsd");
}
}
class Program
{
public static void Main()
{
XmlSchema schema1 = null;
using (XmlTextReader xtr = new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Example.Schema1.xsd")))
{
schema1 = XmlSchema.Read(xtr, new ValidationEventHandler(XSDValidationEventHandler));
xtr.Close();
}
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.XmlResolver = new EmbeddedResourceResolver();
schemaSet.ValidationEventHandler += new ValidationEventHandler(XSDValidationEventHandler);
schemaSet.Add(schema1);
schemaSet.Compile();
XmlSchema compiledSchema = null;
foreach (XmlSchema schema in schemaSet.Schemas())
{
compiledSchema = schema;
}
Console.WriteLine("Finished");
Console.ReadKey();
}
public static void XSDValidationEventHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine(args.Message);
}
}
}

Related

C# - parse xml nodes

I am loading my data from XML using C# this way:
XmlDocument xmlDoc = new XmlDocument();
TextAsset xmlFile = Resources.Load("levels/" + levelID) as TextAsset;
xmlDoc.LoadXml(xmlFile.text);
XmlNodeList levelsList = xmlDoc.GetElementsByTagName("level");
foreach (XmlNode levelInfo in levelsList)
{
XmlNodeList childNodes = levelInfo.ChildNodes;
foreach (XmlNode value in childNodes)
{
switch (value.Name)
{
case "info":
//levelWidth = getInt(value, 0);
//levelHeight = getInt(value, 1);
break;
}
}
}
And heres XML I am loading:
<?xml version="1.0" encoding="utf-8" ?>
<level>
<info w="1000" h="500"/>
</level>
It works just fine, I am now trying to find best way to load child nodes, inside my level node with multiple points nodes inside
<?xml version="1.0" encoding="utf-8" ?>
<level>
<info w="1000" h="500"/>
<ground>
<point val1="val1" val2="val2"/>
</ground>
</level>
I will be grateful for some guidance how to move in the right direction, thank you.
Using XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<level>" +
"<info w=\"1000\" h=\"500\"/>" +
"</level>";
XDocument doc = XDocument.Parse(xml);
XElement level = (XElement)doc.FirstNode;
level.Add("ground", new object[] {
new XElement("point", new XAttribute[] {
new XAttribute("val1", "val1"),
new XAttribute("val2", "val2")
})
});
}
}
}
​
If you need read all points, you can use
var nodeList = Xmldocument.SelectNodes("level/info/ground/point");
SelectNodes return a list of nodes.
I would go for a slidely different way and use a data object. Then you don't have to analyse xml, you just code your data class:
[Serializable()]
public class CLevel
{
public string Info { get; set; }
}
[Serializable()]
public class CDatafile
{
public List<CLevel> LevelList { get; set; }
public CDatafile()
{
LevelList = new List<CLevel>();
}
}
public class DataManager
{
private string FileName = "Data.xml";
public CDatafile Datafile { get; set; }
public DataManager()
{
Datafile = new CDatafile();
}
// Load file
public void LoadFile()
{
if (System.IO.File.Exists(FileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(FileName);
Type tType = Datafile.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
Datafile = (CDatafile)oData;
srReader.Close();
}
}
// Save file
public void SaveFile()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(FileName);
Type tType = Datafile.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, Datafile);
swWriter.Close();
}
}
Then you can use it to create, save and load the file like this:
DataManager dataMng = new DataManager();
// Create some data
CLevel level = new CLevel();
level.Info = "Testlevel";
dataMng.Datafile.LevelList.Add(level);
// Save to file
dataMng.SaveFile();
// Load from file
dataMng.LoadFile();
So you can do everything in code checked by the compiler. Makes life a lot easier, or what do you think?

Getting deserialized values

I have deserialized an xml file which contains a list of programs, days, times and a true or false value against them. The file looks similar to below.
<AlarmSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProgramSettings>
<ProgramSetting>
<ProgramPathText>Alarm.exe</ProgramPathText>
<ProgramPathValue>D:\Documents\Work\Visual Studio\WindowsFormsApplication1\bin\Debug\Alarm.exe</ProgramPathValue>
<Monday>
<Time>11:08</Time>
<Enabled>true</Enabled>
</Monday>
<Tuesday>
<Time>17:08</Time>
<Enabled>true</Enabled>
</Tuesday>
</ProgramSetting>
</ProgramSettings>
</AlarmSettings>
I am trying to access the values but i keep getting stuck at the end of program settings where i cant see any methods that will be useful. I am needing to get to return the programpathtext values, programpathvalue values etc.
public void load()
{
AlarmSettings alarmSettings;
alarmSettings = AlarmSettings.Load(#"C:\Users\jason\Desktop\Booya.txt");
alarmSettings.ProgramSettings.
}
Any help would be appreciated. Thanks
AlarmSettings Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.IO;
namespace WindowsAlarm
{
public class AlarmSettings
{
public List<ProgramSetting> ProgramSettings = new List<ProgramSetting>();
public void Save(string filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(AlarmSettings));
TextWriter writer = new StreamWriter(filename);
serializer.Serialize(writer, this);
writer.Close();
}
public static AlarmSettings Load(string filename)
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(AlarmSettings));
using (StreamReader reader = new StreamReader(filename))
{
AlarmSettings loadedSettings = (AlarmSettings)serializer.Deserialize(reader);
reader.Close();
return loadedSettings;
}
}
catch(Exception e)
{
throw e;
//return new AlarmSettings();
}
}
}
}
if you have proper object structure , make use of XmlSerializer
XmlSerializer serializer = new XmlSerializer(typeof(objecttype));
or make use of Linq to XML or create you own XML parser for that you can serach on google
you can also check post which talks about serialization : Object to XML using LINQ or XmlSerializer
I have solved the problem. the problem was that i was not going in and accessing the collection.
public void load()
{
AlarmSettings alarmSettings;
alarmSettings = AlarmSettings.Load(#"C:\Users\jason\Desktop\Booya.txt");
foreach (var setting in alarmSettings.ProgramSettings)
{
string pathtext = setting.ProgramPathText;
string pathvalue = setting.ProgramPathValue;
}
}

Xml & C# Deserialize Exception Error

I am working on a XNA gaming project and keep receiving the following error:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: There is an error in XML document (2, 2).
This is my Xml code:
<?xml version="1.0" encoding="utf-8" ?>
<SplashScreen>
<Path>\SplashScreen\Game.png</Path>
</SplashScreen>
And this is my C# Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace WindowsGame3
{
public class Manager<T>
{
public Type Type;
public T Load(string Path)
{
T instance;
using (TextReader reader = new StreamReader(Path))
{
XmlSerializer xml = new XmlSerializer(Type);
instance = (T)xml.Deserialize(reader);
}
return instance;
}
public void save(string Path, object obj)
{
using (TextWriter writer = new StreamWriter(Path))
{
XmlSerializer xml = new XmlSerializer(Type);
xml.Serialize(writer, obj);
}
}
}
}
Here's the code that uses the above Manager class:
public void LoadContent(ContentManager Content)
{
this.Content = new ContentManager(Content.ServiceProvider, "Content");
GameScreenManager = new Manager<GameScreen>();
GameScreenManager.Type = currentScreen.Type;
currentScreen = GameScreenManager.Load("SplashScreen.xml");
currentScreen.LoadContent();
}
Did you check to see if the type T that you are calling the Load method on matches proper casing of the root element name SplashScreen ?

Write to Xml File using Asp-C#

I'm trying to store Some values to an xml file.I've already created an Xml file and trying to overwrite data. The code is given..
/*storepassword.cs *//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
public class StorePassword
{
public StorePassword()
{
}
public void store(NewPassword nps)
{
XmlDocument XmlDoc = new XmlDocument();
//XmlDoc.Load(#"Password.xml");
XmlDoc.LoadXml("Password.xml");
XmlNode root = XmlDoc.DocumentElement;
XmlNode myNode1 = root.SelectSingleNode("UserName");
XmlNode myNode2 = root.SelectSingleNode("PassWord");
myNode1.Value = "sjn";
myNode2.Value = "sjn123";
XmlDoc.Save(#"Password.xml");
}
}
//NewPassword.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class NewPassword
{
public NewPassword()
{
}
public string username{ get; set; }
public string Password{ get; set; }
}
on button click..
NewPassword nps = new NewPassword();
nps.username = TxtUser.Text;
nps.Password = TxtNewPassword.Text;
StorePassword sp=new StorePassword();
sp.store(nps);
The existing Xml file contains the following..
<?xml version="1.0" encoding="utf-8"?>
<ROOT>
<UserName>abc</UserName>
<PassWord>123</PassWord>
</ROOT>
But it's not working..
Data at the root level is invalid. Line 1, position 1
this error occures..
Ichanged the code as XmlDoc.Load(#"Password.xml");
now error changed to
Root element is missing.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Xml.XmlException: Root element is missing.
why this happens?
Try using XML Serialization:
public static partial class ObjectXMLSerializer<T> where T : class
{
private static void SaveToDocumentFormat(T serializableObject, System.Type[] extraTypes, string path, IsolatedStorageFile isolatedStorageFolder)
{
using (TextWriter textWriter = CreateTextWriter(isolatedStorageFolder, path))
{
XmlSerializer xmlSerializer = CreateXmlSerializer(extraTypes);
//Cuong: set name space to null
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
xmlSerializer.Serialize(textWriter, serializableObject, ns);
}
}
public static void Save(T serializableObject, string path)
{
SaveToDocumentFormat(serializableObject, null, path, null);
}
}
When you load your Xml you need to use Server.MapPath . XmlDoc.LoadXml(Server.MapPath("Password.xml"));
delete
<?xml version="1.0" encoding="utf-8"?>
from
<?xml version="1.0" encoding="utf-8"?>
<ROOT>
<UserName>abc</UserName>
<PassWord>123</PassWord>
</ROOT>
I do not know why it works but we do that all the time in our code. And yes you should be using XmlDocument.Load not XmlDocument.LoadXml

Namespace Prefixes with IXmlSerializable

Bit confused on the proper decorators to use, or whatever design might be necessary. When serializing a class which is implementing IXmlSerializable is there a way to include the namespace and its prefix in the XmlRoot element?
Class definition for example.
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
[XmlRoot("Classy", Namespace = XML_NS)]
public class TestClass : IXmlSerializable
{
private const string XML_PREFIX = ""; // default namespace
private const string XML_NS = "www.123.com";
private const string XML_MEMBER_PREFIX = "me";
private const string XML_MEMBER_NS = "member.com";
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlsn {
get {
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add(XML_PREFIX, XML_NS);
xsn.Add(XML_MEMBER_PREFIX, XML_MEMBER_NS);
return xsn;
}
}
void IXmlSerializable.WriteXml(XmlWriter writer) {
writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
XML_MEMBER_NS, Member1);
writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
XML_MEMBER_NS, Member2.ToString());
writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
}
//[XmlElement(ElementName = "Member1.5", Namespace = XML_MEMBER_NS)]
public string Member1 {
get { return "init"; }
set { ; }
}
//[XmlElement(ElementName = "Member2.5", Namespace = XML_MEMBER_NS)]
public int Member2 {
get { return 3; }
set { ; }
}
//[XmlElement(ElementName = "Member3.5", Namespace = XML_NS)]
public string Member3 {
get { return "default namespace"; }
set { ; }
}
// ignore ReadXml/GetSchema
XmlSchema IXmlSerializable.GetSchema() { return null; }
void IXmlSerializable.ReadXml(XmlReader reader) { return; }
}
When serialized via:
TestClass tc = new TestClass();
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
ser(writer, tc, tc.xmlsn); // just a plain XmlWriter to Console.Out
the output is
<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns="www.123.com">
<me:Member1.5 xmlns:me="member.com">init</me:Member1.5>
<me:Member2.5 xmlns:me="member.com">3</me:Member2.5>
<Member3.5>default namespace</Member3.5>
</Classy>
The output I was expecting was:
<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns:me="member.com" xmlns="www.123.com">
<me:Member1.5>init</me:Member1.5>
<me:Member2.5>3</me:Member2.5>
<Member3.5>default namespace</Member3.5>
</Classy>
The second is the output of XmlSerializer if the class's implementation of IXmlSerializable is removed and you uncomment the XmlElement decorators. I know both of the Xml documents returned are valid, but it would be nice to try and remove the redundant namespace declarations. I would assume such a thing is possible, since IXmlSerializable is meant to give greater control over how your class is serialized/deserialized.
Update: A very interesting answer suggested modifying the XmlWriterSettings! It looked like this would clear everything up by modifying the NamespaceHandling property. However this still results in the namespaces being rewritten for each member. Full serialization code below:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
TestClass tc = new TestClass();
XmlWriterSettings xmlSet = new XmlWriterSettings();
xmlSet.Encoding = System.Text.Encoding.UTF8;
xmlSet.Indent = true;
xmlSet.NamespaceHandling = NamespaceHandling.OmitDuplicates;
XmlWriter writer = XmlWriter.Create(Console.Out, xmlSet);
ser.Serialize(writer, tc); // with/without tc.xmlsn same result
writer.Flush();
writer.Close();
I simply added an String Attribute to WriteXml. It worked!
void IXmlSerializable.WriteXml(XmlWriter writer) {
writer.WriteAttributeString("xmlns:me", "member.com");
writer.WriteAttributeString("xmlns", "www.123.com");
writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
XML_MEMBER_NS, Member1);
writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
XML_MEMBER_NS, Member2.ToString());
writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
}
and remove [XmlRoot("Classy", Namespace = XML_NS)] and the xmlsn property from the class.
Using the WriteAttributeString as suggested is not completely correct. Here is an example on how to use it correctly:
In the WriteXml method at the beginning add something like this:
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
You need to set XmlWriterSetting for it to work. see below pls
http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.aspx

Categories

Resources