Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

XML Validator - Commandline Tool

2.80/5 (3 votes)
27 Nov 2017CPOL1 min read 12.5K   214  
It is a commandline XML/XSD validator

Introduction

This is a simple command prompt application to validate XML against XSD, i.e., XML schema file.

The intention being a new development is there are situations like running a make file to build a huge package that might include XML files at some point and need to be validated. Those XML files may require a specific rule or data type which checks item’s value range or in other words, user specific datatype.

Background

This is one such tool, exe can be used to make script during package build where validation is needed.

Implemented in C# solution as command based, and C# class DLL for core validation function and for log file. For error logging, log4net.dll is used which is freeware, reason being log4net enables logging simple.

The Code

ValidationUtils.dll - This includes the core implementation class and this DLL is added to solution‘s References.

C#
/// <summary>
/// This function creates an xml reader, and Loads the xml file selected for validation.
/// </summary>
/// <returns>bool</returns>

public bool OpenXmlFileUtils(string xml_path)
{
           if (xmlPath != xml_path)
                xmlPath = xml_path;

           try
            {
                //create a file reader to read xml and copy to string
                reader = XmlReader.Create(xml_path, readerSettings);

               //Load xml file   
                xmlDoc.Load(xml_path);

               //Close file               
               CloseXmlFile(reader);
               bResult = true;
            }
            catch (Exception)
            {
                bResult = false;
            }

            return bResult;
        }

/// <summary>
/// Main function for this tool, Validates xml against xsd with the help of
/// event handler function ValidationEventHandlerUtils.

public void ValidateXMLUtils(string testString, int iCount)
        {
            //initialize it to 0 before any handler called.
            nErrors = 0;

            try
            {
                // Declare local objects
                XmlReaderSettings rs = new XmlReaderSettings();
                rs.ValidationType = ValidationType.Schema;
                rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation |
                XmlSchemaValidationFlags.ReportValidationWarnings;
                // Event Handler for handling exception &
                // this will be called whenever any mismatch between XML & XSD

                rs.ValidationEventHandler += new ValidationEventHandler(ValidationEventHandlerUtils);
                rs.Schemas.Add(null, XmlReader.Create(testString));
                xmlValidatingReader = XmlReader.Create(xmlPath, rs);
                ...
}

/// <summary>
/// Event handler method called by ValidateXMLUtils function.
/// </summary>
 void ValidationEventHandlerUtils(object sender, ValidationEventArgs e)
        {
            //Update failed count
            validationCalledCount++;
            if (e.Severity == XmlSeverityType.Warning)
            {
                validationResultStr = e.Message;
            }
…
}

Logging class implementation (wrapper to log4net APIs):

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;

namespace ValidationUtils
{
    public class LogFile
    {
        public bool results = false;
        //initializes log4net.
        private static readonly ILog logger =
        LogManager.GetLogger(typeof(LogFile));

        //for singleton
        public static LogFile logfile_instance;

        /// <summary>
        /// Ctor
        /// </summary>
        public LogFile()
        {
            log4net.Config.XmlConfigurator.Configure();
        }

        //for singleton
        public static LogFile cpeLogFileInstance
        {
            get
            {
                if (logfile_instance == null)
                {
                    logfile_instance = new LogFile();
                }

                return logfile_instance;
            }
        }
…
}

Example XML and XSD files used to capture output screenshot:

XML

XML
<?xml version="1.0" encoding="UTF-8"?>
<shiporder orderid="150">
  <orderperson>Raghavendra Hosad</orderperson>
  <shipto>
    <name>Raghavendra Hosad</name>
    <address>Green Park 55</address>
    <city>10 HYD</city>
    <country>India</country>
  </shipto>
  <item>
    <title>The Da Vinci Code</title>
    <note>Special Edition</note>
    <quantity>1</quantity>
    <price>8.50</price>
  </item>
  <item>
    <title>Harry Potter and the Goblet of Fire</title>
    <quantity>1</quantity>
    <price>12.30</price>
  </item>
</shiporder>

XSD

XML
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="shiporder">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="orderperson" type="xs:string" />
        <xs:element name="shipto">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string" />
              <xs:element name="address" type="xs:string" />
              <xs:element name="city" type="xs:string" />
              <xs:element name="country" type="xs:string" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element maxOccurs="unbounded" name="item">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="title" type="xs:string" />
              <xs:element minOccurs="0" name="note" type="xs:string" />
              <xs:element name="quantity" type="xs:unsignedByte" />
              <xs:element name="price" type="xs:decimal" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="orderid" type="xs:unsignedByte" use="required" />
    </xs:complexType>
  </xs:element>

  <xs:simpleType name="quantityType">
    <xs:annotation>
      <xs:documentation>carrierIndex range checking.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:unsignedByte">
      <xs:minInclusive value="2"/>
      <xs:maxInclusive value="4"/>
    </xs:restriction>
  </xs:simpleType>
  
</xs:schema>

Result

  1. When validation is success.

    Image 1

  2. When there is validation error.

    Image 2

LogFile.log

A logfile is getting generated at system path C:\Users\<name>\AppData\Local\SchemaValidatorCmdTool\LogFile.log

2017-11-25 1:8:26,972 [9] INFO  -------------------------------------------------------------
2017-11-25 1:8:26,979 [9] ERROR The 'quantity' attribute is invalid
2017-11-25 1:8:26,979 [9] WARN   The value '1' is invalid according to its datatype 'quantityType'
2017-11-25 1:8:26,979 [9] WARN   The MinInclusive constraint failed.
2017-11-25 1:8:26,979 [9] INFO  Total item failed count : 1
2017-11-25 1:8:26,979 [9] INFO  Total item pass count : 15
2017-11-25 1:8:26,979 [9] INFO  -------------------------------------------------------------

Conclusion

I believe choosing a particular schema validator tool depends upon one's requirement. There are GUI implementations of such tools available but as long as we are not bothered about editing an item and need to include during make build, I think this tool (SchemaValidatorCmdTool) is handy and also a LogFile.log generating which can be used for examining additional fail item information.

History

  • 27th November, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)