Created
July 11, 2011 13:50
-
-
Save jonforums/1075878 to your computer and use it in GitHub Desktop.
XML validation with external DTD in .NET experiment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Author: Jon Maken | |
* Creation Date: 5/24/2004 1:03 PM | |
* Version: 0.95, 7/2/2004 | |
* License: Modified BSD License (3-clause) | |
*/ | |
using System; | |
using System.IO; | |
using System.Text; | |
using System.Xml; | |
using System.Xml.Schema; | |
namespace XCheck | |
{ | |
/// <summary> | |
/// XCheck exit codes | |
/// </summary> | |
enum ExitCode | |
{ | |
OK = 0, // XML is well-formed and valid | |
CmdLineErr = -1, // incorrect command line invocation | |
IOErr = -2, // I/O error | |
XmlParseErr = -3, // XML parsing error | |
ValErr = -4, // Validation error | |
} | |
/// <summary> | |
/// <para>Console app that checks if the specified XML file is well formed. | |
/// If the XML file has an embedded DTD/XSD schema reference or a DTD/XSD | |
/// schema location is given on the command line, the XML file will be | |
/// validated against the specified schema.</para> | |
/// <para>NOTE: only a DTD or an XSD location can be provided as a command | |
/// line argument; both can not be specified. | |
/// </para> | |
/// <example>Example command line invocations: | |
/// Well-formed? <c>xcheck test.xml</c> | |
/// Well-formed and valid (DTD)? <c>xcheck test.xml -d valid.dtd rootElement</c> | |
/// Well-formed and valid (XSD)? <c>xcheck test.xml -s valid.xsd</c> | |
/// </example> | |
/// <returns>simple error message to StdErr and integer exit code.</returns> | |
/// </summary> | |
class XCheck | |
{ | |
private static bool valErrFlag = false; | |
private static string usage = | |
"\nFAILED. Usage = xcheck XML_file [-d DTD_file XML_root | -s XSD_file]"; | |
/******************************************************************************* | |
* MAIN METHOD | |
*/ | |
public static int Main(string[] args) | |
{ | |
string xmlFile; // XML file to check | |
string dtdFile; // DTD file that validates XML file | |
string xsdFile; // XSD file that validates XML file | |
string xmlRoot; // root element of XML file | |
FileStream xmlStream = null; // XML file as a FileStream object | |
XmlValidatingReader reader; | |
XmlParserContext context; | |
// check command line arguments and react accordingly | |
switch (args.Length) | |
{ | |
case 1: | |
case 3: | |
case 4: | |
GetArgs(args, out xmlFile, out xmlRoot, | |
out dtdFile, out xsdFile); | |
break; | |
default: | |
Console.Error.WriteLine(usage); | |
return (int) ExitCode.CmdLineErr; | |
} | |
// if DTD argument, build up an XmlParserContext in order to | |
// validate an XML fragment then create an XmlValidatingReader | |
// using a Stream (xmlFile), XmlNodeType (Document) and the | |
// XmlParserContext | |
if (dtdFile != String.Empty && xmlRoot != String.Empty) | |
{ | |
InitParserContext(xmlRoot, dtdFile, out context); | |
try | |
{ | |
xmlStream = new FileStream(xmlFile, FileMode.Open); | |
} | |
catch (Exception) | |
{ | |
Console.Error.WriteLine("\tFAILED. I/O error occurred reading XML file"); | |
Environment.Exit((int) ExitCode.IOErr); | |
} | |
reader = new XmlValidatingReader(xmlStream, | |
XmlNodeType.Document, context); | |
reader.ValidationType = ValidationType.Auto; | |
reader.ValidationEventHandler += | |
new ValidationEventHandler(ValidationCallback); | |
} | |
// else set up a validating reader that automagically recognizes internal | |
// DTD's or XSD schemas and validates accordingly. Hook up a | |
// validation event handler so that all validation errors and warnings | |
// are captured, not just the first one which would throw an XMLException | |
else | |
{ | |
reader = new XmlValidatingReader( | |
new XmlTextReader(xmlFile)); | |
reader.ValidationType = ValidationType.Auto; | |
reader.ValidationEventHandler += | |
new ValidationEventHandler(ValidationCallback); | |
} | |
// if XSD schema argument, add the specified schema to the reader's | |
// XmlSchemaCollection using the namespace defined in the | |
// targetNamespace attribute of the schema by passing null as 1st | |
// arg to Add() | |
if (xsdFile != String.Empty) | |
{ | |
reader.Schemas.Add(null, xsdFile); | |
} | |
// try parsing XML files, catch appropriate exceptions, print | |
// appropriate msgs, and always close the reader. IOException | |
// will handle any file opening issues. | |
try | |
{ | |
while (reader.Read()); | |
} | |
catch (System.IO.IOException) | |
{ | |
Console.Error.WriteLine("\tFAILED. I/O error occurred"); | |
return (int) ExitCode.IOErr; | |
} | |
catch (XmlException e) | |
{ | |
Console.Error.WriteLine(e.Message); | |
return (int) ExitCode.XmlParseErr; | |
} | |
finally | |
{ | |
if (xmlStream != null) | |
xmlStream.Close(); | |
reader.Close(); | |
} | |
// Exit with failure if any validation errors occur, otherwise exit | |
// with success code. Since a validation event handler is defined | |
// validation will continue until all errors are discovered | |
if (!valErrFlag) | |
{ | |
return (int) ExitCode.OK; | |
} | |
else | |
{ | |
return (int) ExitCode.ValErr; | |
} | |
} | |
/******************************************************************************* | |
* METHODS | |
*/ | |
// write validation warning and error messages to StdErr | |
private static void ValidationCallback(object sender, ValidationEventArgs e) | |
{ | |
if (e.Severity == XmlSeverityType.Warning) | |
{ | |
Console.Error.WriteLine("VALIDATION WARNING: " + e.Message); | |
} | |
else | |
{ | |
valErrFlag = true; | |
Console.Error.WriteLine("VALIDATION ERROR: " + e.Message); | |
} | |
} | |
// parse command line and check that specified files exist | |
private static void GetArgs(string[] args, out string xmlFile, | |
out string xmlRoot, out string dtdFile, | |
out string xsdFile) | |
{ | |
int argIndex; | |
// XML file must be the first command line argument | |
if (File.Exists(args[0])) | |
{ | |
xmlFile = args[0]; | |
} | |
else | |
{ | |
xmlFile = String.Empty; | |
} | |
// check and parse DTD file name | |
argIndex = Array.IndexOf(args, "-d"); | |
if (argIndex > 0) | |
{ | |
// ensure # of args is consisent with a DTD | |
// and the XML root element | |
if (args.Length == 4) | |
{ | |
dtdFile = args[argIndex + 1]; | |
xmlRoot = args[argIndex + 2]; | |
if (!File.Exists(dtdFile)) | |
dtdFile = String.Empty; | |
} | |
else | |
{ | |
dtdFile = xmlRoot = null; | |
Console.Error.WriteLine(usage); | |
Environment.Exit((int) ExitCode.CmdLineErr); | |
} | |
} | |
else | |
{ | |
dtdFile = String.Empty; | |
xmlRoot = String.Empty; | |
} | |
// check and parse XSD file name. | |
argIndex = Array.IndexOf(args, "-s"); | |
if (argIndex > 0) | |
{ | |
// ensure # of args consistent | |
if (args.Length == 3) | |
{ | |
xsdFile = args[argIndex + 1]; | |
if (!File.Exists(xsdFile)) | |
xsdFile = String.Empty; | |
} | |
else | |
{ | |
xsdFile = null; | |
Console.Error.WriteLine(usage); | |
Environment.Exit((int) ExitCode.CmdLineErr); | |
} | |
} | |
else | |
{ | |
xsdFile = String.Empty; | |
} | |
} | |
// build context for parser in order to validate with the specified DTD | |
private static void InitParserContext(string xmlRoot, string dtdFile, | |
out XmlParserContext context) | |
{ | |
context = new XmlParserContext(null, // XmlNameTable | |
null, // XmlNamespaceManager | |
xmlRoot, // docTypeName | |
String.Empty, // pubId | |
dtdFile, // sysId | |
String.Empty, // internalSubset | |
String.Empty, // baseURI | |
String.Empty, // xmlLang | |
XmlSpace.Default,// xmlSpace | |
Encoding.UTF8); // Encoding | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment