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

XmlXsdDocument

4.56/5 (4 votes)
27 Oct 200610 min read 1   570  
This article explains the applcation of the XmlXsdDocument class.

Introduction

This article shows a class to contain information about a node from an XmlDocument combined with information from the corresponding XmlSchema.

These classes are the objects to be implemented:

Image 1

Implementation

How do we simultaneously read XML and XSD documents, and build a document which will contain nodes combining information from both documents.

When we need to read information from a XmlDocument file, we use the class System.Xml.XmlDocument. This class not only reads an isolated XML file but can simultaneously read a corresponding XSD schema file and apply the necessary validation during this process.

When we want to intercept this process, we need to implement a class derived from System.Xml.XmlValidatingReader and override the Read method. This method is invoked every time the base class starts or stops reading a node from the XML file. At this point, the base class already contains information about the currently read node, such as: Name, Value, and information which had been extracted from XSD file. Unfortunately, it does not contain crucial information for our objective; it does not have the property that returns the System.Xml.Schema.XmlSchemaElement described by the currently read node.

How can we overcome this obstacle? See these project files: Puma.Xml.XmlValidatingReader.cs, Puma.Xml.XmlXsdNodeBuilder.cs.

For testing, just turn out project properties to \output type\Console application.

Full project static schema:

Image 2

Image 3

Using the code

Puma.Xml.XmlXsdDocument class

This class creates a tree representation of the XML. This tree contains not only the information from the XML but also associated information from the corresponding XSD schema. The tree representation of the XML and associated XSD document enables the navigation and editing of the XML document. Also, this class provides a method for the creation of an XML file from the corresponding XSD.

Restrictions:

This class may process only documents with restricted contents: For example, an element of complexType may have only a sequence child.

Constructors:

public XmlXsdDocument(string XmlFileName, string XsdFileName)

Loads the XML and the XSD documents from the specified files

public XmlXsdDocument(string XsdFileName)

Create an XML file that conforms to the XSD file.

public XmlXsdDocument(string XmlFileName, string XsdFileName, NodeExtensible NodeExtensible)

Loads the XML and the XSD documents from the specified files. When the load occurs, the overridden methods of the NodeExtensible class are invoked.

public XmlXsdDocument(string XsdFileName, NodeExtensible NodeExtensible)

Creates an XML file that conforms to the XSD file. When created, the overridden methods of the NodeExtensible class are invoked.

public XmlXsdDocument(string XsdFileName, ConstructParams ConstructParams, NodeExtensible NodeExtensible)

Create an XML file that conforms to the XSD file and the ConstructParams parameters. When created, the overridden methods of the NodeExtensible class are invoked.

Properties:

public Puma.Xml.XmlDocument XmlDocument

public Puma.Xml.XsdDocument XsdDocument

Methods:

public void Save(string FileName)

Saves the XML document to the specified file.

public void Save()

Saves the XML document to the file from where it was loaded.

public void SaveBin(string FileName)

Saves the XML document to the specified binary file.

Restrictions:

The maxOccurs attribute of each element cannot be unbounded. Each element with a string type must have the maxLength restriction. The type of any element from the document should be recognized by the SaveBin method.

Current version supports: String, Byte, SByte, Int16, Int32, Int64, UInt16, UInt32, UInt64.

Element with an enumeration restriction should have a non-string base type.

Puma.Xml.ConstructParams class

Puma.Xml.ConstructParams.ConstructElementParams class

Properties:

public bool UseMinOccurs = true

When an element is created, the quantity in the document will be equal to the minOccurs attribute. Otherwise, it will be equal to maxOccurs (in this case, maxOccurs should not have the unbounded value).

Puma.Xml.ConstructParams.ConstructDefaultValueParams class

Properties:

public char StringFillChar = ' '

When an element of string type is created that has a minLength restriction, the value is initialized by a string with a length equal to minLength and filled by the StringFillChar character.

System.IO.BinaryReader ValueProvider

When an XML document is created from an XSD schema file, and this parameter is not null, all values of the created XML will be initialized by reading data from this reader.

Restrictions:

See the Puma.Xml.XmlXsdDocument.SaveBeen() restrictions.

Puma.Xml.NodeExtensible class

This class helps to extend the functionality of a document’s node or the document itself. When XmlXsdDocument creates a node in the nodes tree, we can invoke one of methods of this class and initialize the node using the returned object TagEx property. Further, we get easy access to this returned object through the TagEx property of the appropriate node.

Methods:

virtual object OnXmlNodeCreated(Puma.Xml.XmlNode XmlNode)

Invoked when the document has finished creating XmlNode.

virtual object OnXsdNodeCreated(Puma.Xml.XsdNode XsdNode)

Invoked when the document has finished creating XsdNode.

virtual object OnXmlXsdNodeCreated(Puma.Xml.XmlXsdNode XmlXsdNode)

Invoked when the document has finished creating XmlXsdNode.

virtual object OnXmlDocumentCreated(Puma.Xml.XmlDocument XmlDocument)

Invoked when the document has finished creating XmlDocument.

virtual object OnXsdDocumentCreated(Puma.Xml.XsdDocument XsdDocument)

Invoked when the document has finished creating XsdDocument.

virtual object OnXmlXsdDocumentCreated(Puma.Xml.XmlXsdDocument XmlXsdDocument)

Invoked when the document has finished creating itself.

Puma.Xml.XmlXsdNode class

The class contains information about a document node. Since what are part of the document tree have properties, which get access to one child and parent, combined information is extracted from the XML and XSD documents.

Properties:

Puma.Xml.XmlXsdDocument XmlXsdDocument

Document containing this node.

public Puma.Xml.XmlNode XmlNode

Describes the node from the XML document.

public Puma.Xml.XsdNode XsdNode

Describes the node from the XSD document.

object Parent

Retrieve parent (either Puma.Xml.XmlXsdDocument or Puma.Xml.XmlXsdNode type).

public string Name

Retrieve node name.

public bool IsComplexType

Define if the node may have child nodes.

public string Value

Retrieve node value.

public object TypedValue

Retrieve node typed value.

public XmlXsdNodeCollection Childs

Retrieve collection of child nodes.

Puma.Xml.XmlXsdNodeCollection class

Represents a collection of child nodes of a node. Each collection is subdivided into a number of fragments [see XmlXsdNodeCollectionFragment class].

Methods:

public XmlXsdNodeCollectionFragment GetXmlXsdNodeFragment(string FragName)

Get the associated fragment of a collection.

Properties:

public XmlXsdNodeCollectionFragment this[string FragName] { get }

Get the associated fragment of a collection.

Puma.Xml.XmlXsdNodeCollectionFragment class

The class represents a collection of child nodes with the same name. This enables the ability to add nodes to remove nodes from this collection.

Note: A node may contain a collection of child nodes with the same name. This may result when this node is described in the XSD document with attribute maxOccurs > 1, and is encountered in the XML document more than once; all these nodes will be located in one XmlXsdNodeCollectionFragment container. Even in the case of maxOccurs = 1, the single node will be located in a separate XmlXsdNodeCollectionFragment container. Also, a node may have minOccurs = 0, and not be encountered in the XML document. In this case, there will also be a XmlXsdNodeCollectionFragment created.

Example: an XSD document:

XML
<xs:element name="Root">
    <xs:complexType>
      <xs:sequence>
         <xs:element name="Node1" type="xs:unsignedByte" maxOccurs="3"/>
         <xs:element name="Node2" type="xs:unsignedByte" maxOccurs="1"/>
         <xs:element name="Node3" type="xs:unsignedByte" minOccurs="0"/>
       </xs:sequence>
    </xs:complexType>
</xs:element>

XML document:

XML
<Root>
  <Node1>1</Node1>
  <Node1>2</Node1>
  <Node2>3</Node2>
</Root>
C#
foreach(XmlXsdNodeCollectionFragment frag in rootXmlXsdNode)
{
    System.Console.WriteLine("Frag name: " + frag.Name);
    
    Foreach(XmlXsdNode child in frag)
    {
          System.Console.WriteLine("Child name: " + child.Name + 
                                   ", val= " + child.Value);
    }
}

Console:

Frag name: Node1
Child name: Node1, Val = 1
Child name: Node1, Val = 2
Frag name: Node2
Child name: Node2, Val = 3
Frag name: Node3

Properties:

public XsdNode TemplateXsdNode

Return node which contains information, related to the XSD document, about nodes from the current fragment.

public XmlXsdNode this[int Index]

Retrieves a node at the given index.

public XmlXsdNode LastNode

Retrieves the last node. If no node exists, then return null.

public bool IsCanInsert

Define that a node may be added to the fragment.

public bool IsCanRemove

Define that a node may be removed from the fragment.

Methods:

public XmlXsdNode InsertXmlXsdNode(int Index)

This method creates a node based on information contained in the TemplateXsdNode member and inserts that node in the document. The node is inserted after the fragment’s node with the same index. If Index = -1, the node is placed at the end of the fragment.

The value is initialized in this way:

  • If a default value exists for this node, it is applied.
  • If the value has a string type and a minLength restriction, it is initialized with a string of length = minLength and filled with the character ConstructDefaultValueParams.StringFillChar (see the Puma.Xml.ConstructParams class)
  • If the value has the enumeration restriction, it is initialized with the first enumeration value encountered.
  • If the value is a data type value and implements a MinValue static property, it is initialized by this property.
  • If none of these cases is met, the value is initialized as null.

Notes:

Used when creating a complex node when number of sub node elements depend on the ConstructElementParams.UseMinOccurs parameter (see Puma.Xml.ConstructParams class). If this value is true then this number is equal to minOccurs; otherwise it is equal to maxOccurs.

Exceptions:

Puma.Xml.XmlExceptions.ChildCollectionXmlException[ChildCollectionExceptionCode = Puma.Xml.XmlExceptions.ChildCollectionExceptionCode.NodeIndexInvalid]

Occurs when the index of a fragment is out of range (index exceeds the number of elements in the fragment).

Puma.Xml.XmlExceptions.ChildCollectionXmlException[ChildCollectionExceptionCode = Puma.Xml.XmlExceptions.ChildCollectionExceptionCode. MaxOccursLimitExcited]

OOccurs when no node can be added to the fragment (the number of nodes is more than maxOccurs).

Example: XSD document:

XML
<xs:element name="Root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Node1" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Node11" 
                  type="xs:unsignedByte" default="100" />
              <xs:element name="Node12" 
                  type="xs:unsignedByte" minOccurs="3"/>
        <xs:element name="Node13" >
          <xs:simpleType>
            <xs:restriction base="xs:string">
              <xs:maxLength value="5"/>
            </xs:restriction>
          </xs:simpleType>

              <xs:element name="Enum1" pge:ParentValuePart="true">
                <xs:simpleType>
                  <xs:restriction base="xs:unsignedByte">
                    <xs:enumeration value="2"/>
                    <xs:enumeration value="3"/>
                    <xs:enumeration value="8"/>
                  </xs:restriction>
                </xs:simpleType>
              </xs:element>
             </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
</xs:element>

XML document:

XML
<Root>
</Root>
C#
/////////////////////////////////
//Load XML and XSD in Puma.Xml.XmlXsdDocument, get <ROOT> node

Puma.Xml.XmlXsd.XmlXsdNodeCollectionFragment frag = 
                           rootXmlXsdNode["Node1"];

//Use ConstructElementParams.UseMinOccurs = true and
//ConstructDefaultValueParams.StringFillChar = 'x'

Puma.Xml.XmlXsd.XmlXsdNode insertedNode = 
               frag.InsertXmlXsdNode(-1);

Foreach(XmlXsdNodeCollectionFragment insFrag in insertedNode)
{
    System.Console.WriteLine("Frag name: " + insFrag.Name);
    
    Foreach(XmlXsdNode child in insFrag)
    {
          System.Console.WriteLine("Child name: " + 
                 child.Name ", val= " + child.Value);
    }
}

Console:

Frag name: Node11
Child name: Node1, Val = 100
Frag name: Node12
Child name: Node12, Val = 0
Child name: Node12, Val = 0
Child name: Node12, Val = 0
Frag name: Node13
Child name: Node13, Val = xxxxx
Frag name: Enum1
Child name: Enum1, Val = 2

public XmlXsdNode RemoveXmlXsdNode(int Index)

Remove a node with Index from fragment and document.

Exceptions:

Puma.Xml.XmlExceptions.ChildCollectionXmlException[ChildCollectionExceptionCode = Puma.Xml.XmlExceptions.ChildCollectionExceptionCode.NodeIndexInvalid]

Occurs when the index of a fragment is out of range (Index exceeds the number of elements in a fragment).

Puma.Xml.XmlNode class

The class facilitates dealing with the System.Xml.XmlElement class.

Members:

public readonly Puma.Xml.XmlXsdNode container

Get the container of this class.

Properties:

public System.Xml.XmlElement XmlElement

Get the contained System.Xml.XmlElement element.

Puma.Xml.XsdNode class

The class facilitates dealing with the System.Xml.Schema.XmlSchemaElement class.

Members:

public readonly Puma.Xml.XsdSimpleType XsdSimpleType

See the Puma.Xml.XsdSimpleType class

public readonly XmlXsdNode container

Get the container of this class.

Properties:

public System.Xml.Schema.XmlSchemaElement XmlSchemaElement

Get the contained System.Xml.XmlSchemaElement element.

public bool IsComplexType

Return of true indicates that the element has a complex type (contains child nodes).

public Puma.Xml.MinMaxOccurs MinMaxOccurs

Return the minOccurs and maxOccurs node attributes.

public string Annotation

Return node annotation [see xs:annotation].

public bool IsReadOnly

Return indicates that node is read only [see msadata:ReadOnly attribute].

public string Caption

Return node caption [see msdata:Caption attribute].

Puma.Xml.XsdSimpleType class

The class facilitates dealing with information extracted from the XSD document, which describes the type of a node.

Members:

public readonly XsdNode Container

Get the container of this class.

public readonly XmlSimpleTypeRestriction Restriction

Get the restrictions of the node.

Properties:

public System.Xml.Schema.XmlSchemaSimpleType SimpleType

Get the simple type of the node.

public System.Xml.Schema.XmlSchemaDatatype DataType

Get the data type of the node.

public System.Type ValueType

Get the system type associated with the XSD document node type. See MSDN: Mapping XML Data Types to CLR Types.

XmlSimpleTypeRestriction class

The class facilitates dealing with information that is described by the restrictions of the type of the node.

Enum:

C#
public enum XsdSimpleTypeRestriction
{
    MinLength = 0x1,
    MaxLength = 0x10,
    MinValue = 0x100,
    MaxValue = 0x1000,
    Enumeration = 0x10000,
    All = 0x11111
}

This enum defines the restriction type.

Properties:

public System.Xml.Schema.XmlSchemaSimpleTypeRestriction Restriction

Get node System.Xml.Schema.XmlSchemaSimpleTypeRestriction.

public System.Xml.Schema.XmlSchemaObjectCollection Facets

Get node System.Xml.Schema.XmlSchemaSimpleTypeRestriction.

public bool IsEnum

Return indicates if the node type has enumeration restriction.

public bool IsMinValue

Return indicates if the node type has minValue restriction.

public bool IsMaxValue

Return indicates if the node type has maxValue restriction.

public bool IsMinLength

Return indicates if the node type has minLength restriction.

public bool IsMaxLength

Return indicates if the node type has maxLength restriction.

public int MinLengthRestriction

Return the node minLength restriction. If the restriction is not found, return -1.

public int MaxLengthRestriction

Return the node maxLength restriction. If the restriction is not found. return -1.

public EnumerationRestriction EnumerationRestriction

Return node enumeration restriction

Methods:

public object GetRestriction(XsdSimpleTypeRestriction TypeRestriction)

Get restriction by type. If restriction with this type is not found, return null. The type of the returned object may be one of the following: Puma.Xml.EnumerationRestriction, Puma.Xml.MinMaxLengthRestriction, Puma.Xml.MinMaxValueRestriction

public object GetFirstRestrictionValue(XsdSimpleTypeRestriction TypeRestriction)

Get the value of the node restriction by type. If there is more than one restriction with the same type (enumeration for example), return the first.

public object[] GetRestrictions()

Get all type node restrictions. If none found, return null. See the GetRestriction method for information about the type of returned objects.

public object[] GetRestrictions(int TypeRestrictions)

Get an array of type nodes restrictions by type. If none found, return null. See the GetRestriction method for information about the type of the returned objects.

Acknowledgement

Thanks to Arnie Berg for the contribution in this article writing.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here