We help IT Professionals succeed at work.

xml schema validation

Meir Rivkin
Meir Rivkin used Ask the Experts™
on
i'm using configuration file and xsd file for my app installer.

basically, the config is used to perform pre/post installation procedures when upgrading application version:
ExistInstall - current installation
NewInstall - upgrade installation
PreInstall - prior installation/uninstallation
PostInstall - after installation/uninstallation

i.e.
PreInstall in ExistInstall element is procedure/s to take place before uninstall current installation
PostInstall in NewInstall element is procedure/s to take place after upgrade installation complete.

Q: i want to enforce minOccurs=0 and MaxOccurs=1 to the following elements:
NewInstall,ExistInstall,PreInstall,PostInstall,RollbackInstall,Procedures,PrePostProcedures
DailyRestart,InstallationDirectory

my schema looks valid but even if i duplicate one of the elements, the validation still returns true.

cheers




 

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;

namespace XMLValidatorNS
{
    public class XMLValidator
    {
        // Validation Error Message
        static List<string> errorMessage = new List<string>();

        /// <summary>
        /// Gets the error message.
        /// </summary>
        /// <value>The error message.</value>
        public static List<string> ErrorMessage
        {
            get { return XMLValidator.errorMessage; }
        }

        /// <summary>
        /// Validations the handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="System.Xml.Schema.ValidationEventArgs"/> instance containing the event data.</param>
        public static void ValidationHandler(object sender,
                                             ValidationEventArgs args)
        {
            errorMessage.Add(args.Message);
        }


        /// <summary>
        /// Determines whether the specified XML is validated against schema.
        /// </summary>
        /// <param name="xml">The XML.</param>
        /// <param name="schema">The schema.</param>
        /// <returns>
        /// 	<c>true</c> if the specified XML is validated; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValidated(string xml, string schema)
        {
            errorMessage.Clear();
            bool result = false;
            try
            {
                XDocument xdoc = XDocument.Load(xml);
                XmlSchemaSet schemas = new XmlSchemaSet();
                schemas.Add("", XmlReader.Create(schema));

                StringBuilder sb = new StringBuilder();
                xdoc.Validate(schemas, (o, e) =>
                {
                    errorMessage.Add(e.Message);
                }, true);

                result = true;
            }
            catch (Exception error)
            {
                errorMessage.Add(error.Message);
            }

            return result;
        }
    }
}

Open in new window

DeliveryStation.xsd
DeliveryStation.config
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Grant SpiteriSenior consultant

Commented:
So just to clarify you want to ensure that only one instance (MaxOccurs) is available and min occurs = 0 meaning that nothing is mandatory basically??
Grant SpiteriSenior consultant

Commented:
also can you send me some xml that is returning true when it shouldnt be
Grant SpiteriSenior consultant

Commented:
I have run validation on your config file your schema looks valid the config file you have attached is invalid i rearranged the config file to ensure validation then i added an extra preinstall under exist install and it failed validation here is the code i used for the validation:
protected virtual void ValidateXml(string xml, string schema)
        {
            schema = "DeliveryStation.xsd";
            string schemaPath = "C://Downloads//";
            xml = @"<?xml version='1.0' encoding='utf-8'?>
            <configuration xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
              <PrePostProcedures>
	            <ExistInstall>
	              <PreInstall>
                    <Procedures>
                      <ProcedureData path='ds.exe' />
                    </Procedures>
                  </PreInstall>
                  <PostInstall>
                    <Procedures>
                      <ProcedureData path='ds.exe' />
                    </Procedures>
                  </PostInstall>
                </ExistInstall>
                <NewInstall>
	              <PreInstall>
                    <Procedures>
                      <ProcedureData path='ds.exe' />
                    </Procedures>
                  </PreInstall>
                  <PostInstall>
                    <Procedures>
                      <ProcedureData path='ds.exe' />
                    </Procedures>
                  </PostInstall>
                </NewInstall>
	            <RollbackInstall>
                    <Procedures>
                      <ProcedureData path='ds.exe' />
                    </Procedures>
                </RollbackInstall>
	            </PrePostProcedures>
                <InstallationDirectory>c:\program files</InstallationDirectory>
              <DailyRestart enable='true' value='2001-12-17T09:30:47.0Z'/>
            </configuration>";
            try
            {
                ConfigHelper cfgHelper = new ConfigHelper();
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ValidationType = ValidationType.Schema;
                settings.Schemas.Add(string.Empty, string.Format("{0}{1}", schemaPath, schema));

                using (XmlReader reader = XmlReader.Create(new StringReader(xml), settings))
                    while (reader.Read()) { }
            }
            catch (Exception)
            {
                throw;
            }
        }

Open in new window

Meir RivkinFull stack Software Engineer

Author

Commented:
it should return false when the following elements are more than one occurence:
NewInstall ,ExistInstall ,PreInstall,PostInstall,PrePostProcedures,Procedures
i want to use the complex types i've created in the schema but in conjunction with the constraints i've described here.
Full stack Software Engineer
Commented:
i found it.
i should have change the complexType type to xs:all, that will enforce only one element occurrence and won't restrict sequence so i can change the order of elements.
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML Studio Designer Edition 8.1.2.2399 (http://www.liquid-technologies.com)-->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="configuration">
        <xs:complexType>
            <xs:all>
                <xs:element name="PrePostProcedures" minOccurs="0">
                    <xs:complexType>
                        <xs:all>
                            <xs:element name="ExistInstall" type="InstallType" minOccurs="0" maxOccurs="1" />
                            <xs:element name="NewInstall" type="InstallType" minOccurs="0" maxOccurs="1" />
                            <xs:element name="RollbackInstall" type="InstallPhase" minOccurs="0" maxOccurs="1" />
                        </xs:all>
                    </xs:complexType>
                </xs:element>
                <xs:element name="InstallationDirectory" type="xs:string" minOccurs="0" maxOccurs="1" />
                <xs:element name="DailyRestart" type="DailyRestart" minOccurs="0" maxOccurs="1" />
            </xs:all>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="DailyRestart">
        <xs:attribute name="enable" type="xs:boolean" use="required" />
        <xs:attribute name="value" type="xs:time" use="optional" />
    </xs:complexType>
    <xs:complexType name="InstallPhase">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Procedures" minOccurs="1">
                <xs:complexType>
                    <xs:sequence maxOccurs="unbounded">
                        <xs:element name="ProcedureData" type="ProcedureData" />
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="folder" type="xs:string" use="optional" />
    </xs:complexType>
    <xs:complexType name="InstallType">
        <xs:all>
            <xs:element name="PreInstall" type="InstallPhase" />
            <xs:element name="PostInstall" type="InstallPhase" />
        </xs:all>
    </xs:complexType>
    <xs:complexType name="ProcedureData">
        <xs:attribute name="priority" type="xs:int" use="optional" />
        <xs:attribute name="path" type="xs:string" use="required" />
        <xs:attribute name="params" type="xs:string" use="optional" />
        <xs:attribute name="async" type="xs:boolean" use="optional" />
    </xs:complexType>
</xs:schema>

Open in new window