Validate XSL Against XML
 
Published: 13 Feb 2008
Abstract
In this Article, Haissam Abdul Malak shows how to create a class library for validating a certain XSL file against an XML file. He examines the concept with the help of a series of steps with relevant source code and explanations. Finally, he describes how to test the class library which was created in the previous steps.
by Haissam Abdul Malak
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 28141/ 68

Introduction

I was working on a project where the user is required to provide his or her own XSL file to generate his or her own HTML page based on an XML file we provide. In this situation, the need to verify that the XSL file will display appropriate results and not an empty page is required. Because the requirement forced us to only display the HTML page when all the tags used in the XSL file exists in the XML file, is why I realized that we need to create a class library to catch this type of error.

The general steps of this article will be:

1.    Create a Class library project

2.    Create three methods: 1 public and 2 private

3.    Create a property which returns a Hash table containing the invalid Nodes in XSL file

4.    Test the class library

Steps

Create a class library project

First, open Visual Studio 2005, click on file/New project and choose Visual C# Class library.

Name the project as XslValidator. Import Two namespaces.

1.    System.Xml

2.    System.Collections

Writing the Class Library Code

In this section, we will write the necessary code for this class library to work. First, we will create 4 fields.

Listing 1

private  XmlDocument xslDoc = null;
private XmlDocument xmlDoc = null;
private bool IsValidTag = false;
public Hashtable htTagValidation = new Hashtable();

In the above code, we declared 2 XML documents; one for the XSL file and the other for the XML file. One Boolean variable (IsValidTag) is declared to hold true (if a specific tag in the XSL exists in the XML file) or false (if a specific tag in the XSL does not exist in the XML file) and finally, a hash table to contain each tag in the XSL file as a key and a Boolean variable (true/false) as a value.

In below code list, we will add the constructor for this class which takes two parameters; the first is the absolute path for the XSL file and the second is the absolute path for the XSL file. In this constructor, first we instantiated a new object of the XmlDocument class to load the XSL file then we instantiated another new object of the XmlDocument class to load the XML file.

Listing 2

// Load Xsl Document
xslDoc = new XmlDocument();
xslDoc.Load(xsltFilePath);
 
// Load the Xml Document 
xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFilePath);

In the below listing, we will create a function called CheckTags which will take a specific node as a parameter. This is a recursive function and its goal is to loop through the entire XSL file, get each tag referencing a node in the XML file and check if that tag exists in the XML file. As we are looping through all the tags in the XSL file, we will get all the attributes for a specific tag and again loop through them, once the attribute starts with "Page" (the root node of our XML file), we call another method "CheckNodeInXml" (we will see the details of this method later). Finally, we will check if the hash table contains in its value false then we will return false. This method returns true if no value in the hash table is equal to false which means that the validation passed or false if at least one value in the hash table is equal to false which means that the validation failed.

Listing 3

private bool CheckTags(XmlNode currentNode)
{
  // Loop through all the child nodes of the currentNode
  foreach (XmlNode node in currentNode.ChildNodes)
  {
   // Get the attributes of the currentNode to get the node we need to 
   // check its matching in the xml file
    XmlAttributeCollection currentNodeAttributes = node.Attributes;
    if (currentNodeAttributes != null)
    {
      foreach (XmlAttribute currentNodeAttribute in currentNodeAttributes)
      {
        // Checking if the currentNode contains "Page" then we need to compare
        if (currentNodeAttribute.Value.Contains("Page/"))
        {
          // Check its matching
          this.CheckNodeInXml(currentNodeAttribute.Value);
          // if Doesnt match then break directly and return false;
          if (!IsValidTag)
          {
            break;
          }
        }
      }
    }
    if (node.Value != null && node.Value.Contains("Page/"))
    {
      // Check if a match exists
      this.CheckNodeInXml(node.Value);
 
      // If no match then break;
      if (IsValidTag == false)
      {
        break;
      }
    }
 
    if (currentNode.ChildNodes.Count > 0)
    {
      // Call this function with the current node
      CheckTags(node);
    }
  }
    if (htTagValidation.ContainsValue(false) || htTagValidation.Count == 0)
  {
    // if all the nodes are true it returns true, if 1 node is 
    // false then it return false;
    return false;
  }
  else
    return true;
}

In the below listing, the CheckNodeInXml takes the tag (retrieved from the XSL) and looping through all the nodes inside the XML file to check if it does not exists and then the IsValidTag variable is set to false. Finally, each tag in the XSL file will be added to the hash table key and its value will be true if the tag exists in the XML file or false if the tag does not exist. In this case, when we want to display the message for the user containing all the invalid tags all we have to do is to loop through the hash table and check which key value is set to false.

Listing 4

private void CheckNodeInXml(string nodeToBeChecked)
{
  // Create a boolean variable with default value "false"
  bool isValid = false;
  // Loop through all the nodes in the xml file
  foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
  {
    // Get for example "Document" from the node to be checked in the 
    // xml file from the xslt file
    string[]nodeToBeCheckedSplitted = nodeToBeChecked.Split('/');
    // Check if the node contains this value then it exists 
    // and set the boolean variable to true
    if (node.Name.Contains
      (nodeToBeCheckedSplitted[nodeToBeCheckedSplitted.Length - 2]))
    {
      isValid = true;
    }
    // dispose objects
    nodeToBeCheckedSplitted = null;
  }
  IsValidTag = isValid;
  // Set the field isValidTag to the local isValid variable
  htTagValidation.Add(nodeToBeChecked, isValid);
}

The below listing is a property returning a hash table for the developer to be used if he or she wants to display each invalid tag found in the XSL file for the user. This can be very useful if you want to display which tag is invalid to force the user to modify the XSL before being able to view the transformation.

Listing 5

public Hashtable InvalidTags
{
  get
  {
    return htTagValidation;
  }
}

Listing 6

public Boolean Validate()
{
  return this.CheckTags(xslDoc.DocumentElement);
}

The above method is a public method which returns a boolean variable retrieved from Checktags method.

After you finish adding all the above code, build the project to compile it into a DLL file found in the bin folder of the current project directory.

Testing the Class Library

In this section, we will create a web application project to test our class library. Add a reference to the class library inside your web application by right clicking on the References node in the solution explorer then browse to the class library project bin folder and finally select the xsltValidator.dll file. Create a sample XML file inside the root application folder (Default.xml) containing the Listing below.

Listing 7

<?xml version="1.0"?>
<Page>
  <Document>
    <Value>Hello World</Value>
  </Document>
</Page>

Also us the one XSL file (Default.xsl) containing the Listing below.

Listing 8

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html>
     <body style="font-family:Verdana;">
       <xsl:value-of select="Page/Document1/Value"/>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
 

We will use the Page_load event of the default.aspx page to apply the validation; simply copy the below code inside this event.

Listing 9

XslValidator validator = new XslValidator(Server.MapPath("~/Default.xsl"),
  Server.MapPath("~/Default.xml"));
if (!validator.Validate())
{
  Hashtable hs = new Hashtable();
  hs = validator.htTagValidation;
  foreach (object s in hs.Keys)
  {
    if (!(bool)hs[s])
      Response.Write(s.ToString() + " doesnt exist in xml file <br/>");
  }

First, we instantiated a new object from XslValidator class and send the absolute path of both XML and XSL file as parameters. We checked if the validation failed, create a new hash table and set it to the one returned from our class library. A loop into the hash table keys is required to check each object's value if it is false to add it to the response object to be displayed for the user.

In this case, the validation will fail because "Document1" node does not exist in the XML file. If you want to be sure that this validation works properly, just change the "Document1" found in the XSL file by "Document." Of course, it is just a sample XSL file, but I assure you it works perfectly even on a more complex XSL file.

Conclusion

In this article we saw how to create an XslValidator class which can be required in specific times. Node that recursive function was needed in this example to make the code loop through all the nested tags inside the XSL file. Once again, XSL can be very powerful technology if you know the proper way to use it.



User Comments

Title: Best   
Name: Hemant
Date: 2008-02-22 4:27:19 PM
Comment:
good article
Title: Nice Article   
Name: Kamran Shahid
Date: 2008-02-13 2:14:58 AM
Comment:
Very nice article.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2019 ASPAlliance.com  |  Page Processed at 2019-08-21 6:36:01 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search