Xml validation using XSD schema - c#

The following code helps me validate an XML file with an XSD schema.
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(null, xsdFilePath);
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(settings_ValidationEventHandler);
XmlDocument document = new XmlDocument();
document.Load(xmlFilePath);
XmlReader rdr = XmlReader.Create(new StringReader(document.InnerXml), settings);
while (rdr.Read())
{
}
isValid = true;
The ValidationEventHandler also tells me what the errors are, but doesn't tell me on 'where' or 'on which line' they are located. Is there any way to get the line number where the XML fails to be validated?

Would not this do what you are after ?
Create an XmlReaderSettings object and enable warnings through that object.
Unfortunately, there seems to be no way to pass your own XmlReaderSettings object to XmlDocument.Validate().
Instead, you can use a validating XmlReader and an XmlNodeReader to validate an existing XmlDocument (using a XmlNodeReader with StringReader rather than an XmlDocument)
XmlDocument x = new XmlDocument();
x.LoadXml(XmlSource);
XmlReaderSettings settings = new XmlReaderSettings();
settings.CloseInput = true;
settings.ValidationEventHandler += Handler;
settings.ValidationType = ValidationType.Schema;
settings.Schemas.Add(null, ExtendedTreeViewSchema);
settings.ValidationFlags =
XmlSchemaValidationFlags.ReportValidationWarnings |
XmlSchemaValidationFlags.ProcessIdentityConstraints |
XmlSchemaValidationFlags.ProcessInlineSchema |
XmlSchemaValidationFlags.ProcessSchemaLocation ;
StringReader r = new StringReader(XmlSource);
using (XmlReader validatingReader = XmlReader.Create(r, settings)) {
while (validatingReader.Read()) { /* just loop through document */ }
}
And the handler:
private static void Handler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error || e.Severity == XmlSeverityType.Warning)
System.Diagnostics.Trace.WriteLine(
String.Format("Line: {0}, Position: {1} \"{2}\"",
e.Exception.LineNumber, e.Exception.LinePosition, e.Exception.Message));
}

ValidationEventArgs.Message includes line/column in its text.
ValidationEventArgs.Exception has fields for line and column.

Related

XML file using C# and data from SQL Server

Can we create an XML file using C# and data from SQL Server.
The data in the XML File should look something like, "The temp on 10/10/2012 at 10:10:10 AM is 76 degrees Fahrenheit"
The date, time and temperature are taken from SQL Server database.
The Query is: Select Date,Time,IndoorTemp from ThermData
Do pls help me in getting the code for the above XML File. I have absolute no idea on how to work in C#.
you can use xmlserializer to build the xml file
see http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
XmlDocument XD = new XmlDocument();
XmlNode Root = XD.AppendChild(XD.CreateElement("Root"));
XmlNode Child = Root.AppendChild(XD.CreateElement("Child"));
XmlAttribute ChildAtt = Child.Attributes.Append(XD.CreateAttribute("Attribute"));
ChildAtt.InnerText = "My innertext";
Child.InnerText = "Node Innertext";
XD.Save("Add.xml");
do something like this.
You could use an XmlWriter to perform the necessary action and use an XmlReader to reference this against an XSD.
using (XmlWriter writer = XmlWriter.Create(FilePath + FileName))
{
writer.WriteStartDocument();
writer.LookupPrefix("xs");
writer.WriteStartElement("TestForXML");
foreach (DataRow currentRow in dt.Rows)
{
writer.WriteStartElement("Test");
writer.WriteElementString("", Convert.ToString(currentRow[""]));
writer.WriteElementString("", Convert.ToString(currentRow[""]));
//writer.WriteElementString("", "");
writer.WriteElementString("", "");
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
System.IO.FileInfo f = new System.IO.FileInfo(FilePath + FileName);
string destinationFileName = System.IO.Path.GetFileNameWithoutExtension(FilePath + f.Name) + System.DateTime.Now.ToString("ddMMyy_HHmmss") + ".xml";
f.CopyTo (FilePath + destinationFileName);
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(null, FilePath + XSDFile);
settings.ValidationType = ValidationType.Schema;
XmlDocument document = new XmlDocument();
document.Load(FilePath + FileName);
XmlReader rdr = XmlReader.Create(new StringReader(document.InnerXml), settings);
while(rdr.Read()){}

XDocument with inline schema. SchemaInfo is null

OK, so here we go. I've got a set of XML documents that I'm loading into my app. In my little test I've created a reader that validates against the schema specified by the XML document. Using the following code it works quite nicely.
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Create the XmlReader object.
XmlReader reader = XmlReader.Create("xml/note.xml", settings);
// Load the XDocument from the reader
XDocument loadedDoc = XDocument.Load(reader);
Now my XML document gets loaded correctly and any validation errors that occur are handled by the callback.
However, if I want to get schema information about an element by calling GetSchemaInfo() on said element, I'm given null. This question here talks about using an overloaded Validate method, but that doesn't really apply to this situation, unless I'm missing something.
Is it possible to get the schema info loaded into the XDoc using an inline schema or should I be doing this another way?
Check out my answer to my own question.
The first paragraph after the code block is what is important to you, but basically, the SchemaInfo will be there, but it is not added until after the validation callback.
The workaround I used was basically this (NOTE: this code was tested and works when loading an XML directly and calling XDocument.Validate on an XmlSchemaSet, but the premise should be the same or similar with XmlReader and inline schemas):
List<XElement> errorElements = new List<XElement>();
serializedObject.Validate((sender, args) =>
{
var exception = (args.Exception as XmlSchemaValidationException);
if (exception != null)
{
var element = (exception.SourceObject as XElement);
if (element != null)
errorElements.Add(element);
}
});
foreach element in errorElements
{
var si = element.GetSchemaInfo;
// do something with SchemaInfo
}
I was only trying to capture SchemaInfo for elements, hence the as cast and null check, but this should work for other node types like Attributes (not tested though, so i could be wrong).
If you are looking to use a specific callback method instead of an anonymous delegate, your errorElements will need to be a class level field and you can do what you need to do with it after the validation is complete (again, I will add in the untested tag).
public class SomeClass
{
List<XElement> errorElements = new List<XElement>();
public void Load()
{
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Create the XmlReader object.
XmlReader reader = XmlReader.Create("xml/note.xml", settings);
// Load the XDocument from the reader
XDocument loadedDoc = XDocument.Load(reader);
// do something with errorElements
}
public void ValidationCallBack(object sender, ValidationEventArgs e)
{
var exception = (args.Exception as XmlSchemaValidationException);
if (exception != null)
{
var element = (exception.SourceObject as XElement);
if (element != null)
errorElements.Add(element);
}
}
}
In response to your comment about wanting the IXSchemaInfo for all nodes, the Schema info is added to the XElement after the validation regardless of whether the node failed or passed, so your requirement would actually be easier since you do not need to keep a list of failed nodes. You should be able to do this:
public void Load()
{
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Create the XmlReader object.
XmlReader reader = XmlReader.Create("xml/note.xml", settings);
// Load the XDocument from the reader
XDocument loadedDoc = XDocument.Load(reader);
foreach (var node in loadedDoc.Descendants())
{
var si = node.GetSchemaInfo();
}
}
The above example will only access the XElements in your XDocument but it is just to illustrate my point. Once the loading is complete and the xml is validate, the schema info should be there.

How keep carriage return from parsing XML

I am looking on Internet how keep the carriage return from XML data but I could not find the answer, so I'm here :)
The objective is to write in a file the content of a XML data. So, if the value of the node contains some "\r\n" data, the soft need to write them in file in order to create new line, but it doesn't write, even with space:preserve.
Here is my test class:
XElement xRootNode = new XElement("DOCS");
XElement xData = null;
//XNamespace ns = XNamespace.Xml;
//XAttribute spacePreserve = new XAttribute(ns+"space", "preserve");
//xRootNode.Add(spacePreserve);
xData = new XElement("DOC");
xData.Add(new XAttribute("FILENAME", "c:\\titi\\prout.txt"));
xData.Add(new XAttribute("MODE", "APPEND"));
xData.Add("Hi my name is Baptiste\r\nI'm a lazy boy");
xRootNode.Add(xData);
bool result = Tools.writeToFile(xRootNode.ToString());
And here is my process class:
try
{
XElement xRootNode = XElement.Parse(xmlInputFiles);
String filename = xRootNode.Element(xNodeDoc).Attribute(xAttributeFilename).Value.ToString();
Boolean mode = false;
try
{
mode = xRootNode.Element(xNodeDoc).Attribute(xWriteMode).Value.ToString().ToUpper().Equals(xWriteModeAppend);
}
catch (Exception e)
{
mode = false;
}
String value = xRootNode.Element(xNodeDoc).Value;
StreamWriter destFile = new StreamWriter(filename, mode, System.Text.Encoding.Unicode);
destFile.Write(value);
destFile.Close();
return true;
}
catch (Exception e)
{
return false;
}
Does anybody have an idea?
If you want to preserve cr lf in element or attribute content when saving a XDocument or XElement you can do that by using certain XmlWriterSettings, namely NewLineHandling to Entitize:
string fileName = "XmlOuputTest1.xml";
string attValue = "Line1.\r\nLine2.";
string elementValue = "Line1.\r\nLine2.\r\nLine3.";
XmlWriterSettings xws = new XmlWriterSettings();
xws.NewLineHandling = NewLineHandling.Entitize;
XDocument doc = new XDocument(new XElement("root",
new XAttribute("test", attValue),
elementValue));
using (XmlWriter xw = XmlWriter.Create(fileName, xws))
{
doc.Save(xw);
}
doc = XDocument.Load(fileName);
Console.WriteLine("att value: {0}; element value: {1}.",
attValue == doc.Root.Attribute("test").Value,
elementValue == doc.Root.Value);
In that example the value are preserved in the round trip of saving and loading as the output of the sample is "att value: True; element value: True."
Heres a useful link I found for parsing an Xml string with carraige returns, line feeds in it.
howto-correctly-parse-using-xelementparse-for-strings-that-contain-newline-character-in
It may help those who are parsing an Xml string.
For those who can't be bothered to click it says use an XmlTextReader instead
XmlTextReader xtr = new XmlTextReader(new StringReader(xml));
XElement items = XElement.Load(xtr);
foreach (string desc in items.Elements("Item").Select(i => (string)i.Attribute("Description")))
{
Console.WriteLine("|{0}|", desc);
}

Reading XML comments in C#

I have got some XML files that contain comments above the nodes. When I am reading the file in, as part of the process I would like to get the comment out as well. I know you can write a comment to the file using XmlComment, but not sure how to read them back out.
My XML looks similar to this:
<Objects>
<!--Comment about node-->
<GUID-bf2401c0-ef5e-4d20-9d20-a2451a199362>
<info job="SAVE" person="Joe" />
<info job="SAVE" person="Sally" />
</GUID-bf2401c0-ef5e-4d20-9d20-a2451a199362>
<!--Another Comment about node-->
<GUID-bf2401c0-ef5e-4d20-9d20-a5844113284112>
<info job="SAVE" person="John" />
<info job="SAVE" person="Julie" />
</GUID-bf2401c0-ef5e-4d20-9d20-a5844113284112>
Try this:
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreComments = false;
using (XmlReader reader = XmlReader.Create("input.xml", readerSettings))
{
XmlDocument myData = new XmlDocument();
myData.Load(reader);
// etc...
}
To read comments:
XmlReader xmlRdr = XmlReader.Create("Test.XML");
// Parse the file
while (xmlRdr.Read())
{
switch (xmlRdr.NodeType)
{
case XmlNodeType.Element:
// You may need to capture the last element to provide a context
// for any comments you come across... so copy xmlRdr.Name, etc.
break;
case XmlNodeType.Comment:
// Do something with xmlRdr.value
Using System.Xml.Linq:
var doc = XElement.Load(fileName);
var comments = doc.DescendantNodes().OfType<XComment>();
foreach (XComment comment in comments)
...
They are a part of the child nodes of the containing node as all other nodes: http://msdn.microsoft.com/en-us/library/system.xml.xmlcomment.aspx
I know the question is very old, but yesterday I had the same problem. So here is my solution:
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = false;
settings.IgnoreComments = false;
XmlReaderSettings settings2 = new XmlReaderSettings();
settings2.IgnoreWhitespace = false;
settings2.IgnoreComments = false;
XmlReader xmlreaderOriginalCfg = XmlReader.Create(#"C:\...xml", settings);
XmlReader xmlreaderVerificationCfg = XmlReader.Create(#"C:\....xml", settings);
XmlDocument myData = new XmlDocument();
myData.Load(xmlreaderOriginalCfg);
XmlDocument myData2 = new XmlDocument();
myData2.Load(xmlreaderVerificationCfg);
XmlNode parentNode = myData.SelectSingleNode("/configuration/appSettings");
foreach (XmlComment comment in myData2.SelectNodes("//comment()"))
{
XmlComment importedCom = myData.CreateComment(comment.Value);
parentNode.AppendChild(importedCom);
foreach (XmlNode node in myData2.DocumentElement.SelectNodes("/configuration/appSettings/add"))
{
XmlNode imported = myData.ImportNode(node, true);
parentNode.AppendChild(imported);
}
}
myData.Save(this.pathNew);
Maybe it helps somebody
I stored your XML into a file, here is the code sample.
XmlDocument document = new XmlDocument();
document.Load("test.xml");
foreach (XmlComment comment in document.SelectNodes("//comment()"))
{
Console.WriteLine("Comment: \"{0}\".", comment.Value);
}
Some sample code on how to access comments hope this helps
using System;
using System.IO;
using System.Xml;
public class Sample {
public static void Main() {
XmlDocument doc = new XmlDocument();
doc.LoadXml(#"<Objects><!--Comment about node--><othernode/><!--Some more comment--></Objects>");
XmlNode root = doc.FirstChild;
if (root.HasChildNodes)
{
for (int i=0; i<root.ChildNodes.Count; i++)
{
if( root.ChildNodes[i] is XmlComment)
Console.WriteLine(root.ChildNodes[i].InnerText);
}
}
}
}

Possible to validate xml against xsd using code at runtime?

I have xml files that I read in at runtime, is is possible to validate the xml against an xsd file at runtime? using c#
Try this:
public void ValidateXmlDocument(
XmlReader documentToValidate, string schemaPath)
{
XmlSchema schema;
using (var schemaReader = XmlReader.Create(schemaPath))
{
schema = XmlSchema.Read(schemaReader, ValidationEventHandler);
}
var schemas = new XmlSchemaSet();
schemas.Add(schema);
var settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = schemas;
settings.ValidationFlags =
XmlSchemaValidationFlags.ProcessIdentityConstraints |
XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += ValidationEventHandler;
using (var validationReader = XmlReader.Create(documentToValidate, settings))
{
while (validationReader.Read())
{
}
}
}
private static void ValidationEventHandler(
object sender, ValidationEventArgs args)
{
if (args.Severity == XmlSeverityType.Error)
{
throw args.Exception;
}
Debug.WriteLine(args.Message);
}
I GOT CODE TOO! I use this in my tests:
public static bool IsValid(XElement element, params string[] schemas)
{
XmlSchemaSet xsd = new XmlSchemaSet();
XmlReader xr = null;
foreach (string s in schemas)
{ // eh, leak 'em.
xr = XmlReader.Create(
new MemoryStream(Encoding.Default.GetBytes(s)));
xsd.Add(null, xr);
}
XDocument doc = new XDocument(element);
var errored = false;
doc.Validate(xsd, (o, e) => errored = true);
if (errored)
return false;
// If this doesn't fail, there's an issue with the XSD.
XNamespace xn = XNamespace.Get(
element.GetDefaultNamespace().NamespaceName);
XElement fail = new XElement(xn + "omgwtflolj/k");
fail.SetAttributeValue("xmlns", xn.NamespaceName);
doc = new XDocument(fail);
var fired = false;
doc.Validate(xsd, (o, e) => fired = true);
return fired;
}
This one takes in the schemas as strings (file resources within the assembly) and adds them to a schema set. I validate and if its not valid I return false.
If the xml isn't found to be invalid, I do a negative check to make sure my schemas aren't screwed up. Its not guaranteed foolproof, but I have used this to find errors in my schemas.
simpler solution..
try
{
XmlReaderSettings Xsettings = new XmlReaderSettings();
Xsettings.Schemas.Add(null, "personDivideSchema.xsd");
Xsettings.ValidationType = ValidationType.Schema;
XmlDocument document = new XmlDocument();
document.Load("person.xml");
XmlReader reader = XmlReader.Create(new StringReader(document.InnerXml), Xsettings);
while (reader.Read());
}
catch (Exception e)
{
Console.WriteLine(e.Message.ToString());
}

Categories