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.