C#, Xml and Xslt
This is a bonus file from snippets of XML related code I wrote about 12 years ago. Some code may be useful to you. Some code will be superceded by more modern methods and frameworks. Happy Hunting!
-
Read an xml file into a string
using System; using System.IO; using System.Xml; class WriteXMLToString { //read an xml file and then write to a string //(no error checking) public static void Main(string[] args) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(args[0]); StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.Formatting = Formatting.Indented; xmlDocument.WriteTo(xmlTextWriter); xmlTextWriter.Flush(); Console.Write(stringWriter.ToString()); } }
How to read an xml file, twist it with an xsl file and then write to a string (no error checking)
using System; using System.IO; using System.Xml; using System.Xml.Xsl; class WriteXMLViaXSL { //read an xml file, twist it with an xsl file and then write to a string (no error checking) public static void Main(string[] args) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(args[0]); XslTransform xslTransform = new XslTransform(); xslTransform.Load(args[1]); StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.Formatting = Formatting.Indented; xslTransform.Transform(xmlDocument, null, xmlTextWriter); xmlTextWriter.Flush(); Console.Write(stringWriter.ToString()); } }
- Another example reading xml and xslt info from two files and transforming with the more modern XslCompiledTransform
[Test] public void Transform() { const string xmlFileNameWithPath = @"C:\workfiles\SwitchBoard\SwitchBoardHandler\Tests\Incidence1.xml"; const string xslFileNameWithPath = @"C:\workfiles\SwitchBoard\SwitchBoardHandler\xslt\Incidence.xslt"; XslCompiledTransform xslCompiledTransform = new XslCompiledTransform(); xslCompiledTransform.Load(xslFileNameWithPath); StringBuilder stringBuilder = new StringBuilder(); StringWriter stringWriter = new StringWriter(stringBuilder); xslCompiledTransform.Transform(xmlFileNameWithPath, null, stringWriter); stringWriter.Close(); Console.Out.WriteLine("sb.ToString() = {0}", stringBuilder.ToString()); }
- Transforming an xml string with an xslt file
[Test] public void Transform() { const string xmlFileNameWithPath = @"C:\workfiles\SwitchBoard\SwitchBoardHandler\Tests\Incidence1.xml"; const string xslFileNameWithPath = @"C:\workfiles\SwitchBoard\SwitchBoardHandler\xslt\Incidence.xslt"; string xmlString = GetFileAsString(xmlFileNameWithPath); XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(xmlString)); XslCompiledTransform xslCompiledTransform = new XslCompiledTransform(); xslCompiledTransform.Load(xslFileNameWithPath); StringBuilder stringBuilder = new StringBuilder(); StringWriter stringWriter = new StringWriter(stringBuilder); xslCompiledTransform.Transform(xmlTextReader, null, stringWriter); stringWriter.Close(); Console.Out.WriteLine("sb.ToString() = {0}", stringBuilder.ToString()); }
- How to transform an xml string with an xsl string
// <summary> /// transforms an xml string with an xsl string /// </summary> /// <param name="xmlString">xml to transform</param> /// <param name="XSLStylesheet">stylesheet</param> /// <returns>xml transformed</returns> public static string TransformXmlStringWithXslString(string xmlString, string XSLStylesheet) { //process our xml XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(xmlString)); XPathDocument xPathDocument = new XPathDocument(xmlTextReader); //process the xsl XmlTextReader xmlTextReaderXslt = new XmlTextReader(new StringReader(XSLStylesheet)); XslCompiledTransform xslCompiledTransform = new XslCompiledTransform(); xslCompiledTransform.Load(xmlTextReaderXslt); //handle the output stream StringBuilder stringBuilder = new StringBuilder(); TextWriter textWriter = new StringWriter(stringBuilder); //do the transform xslCompiledTransform.Transform(xPathDocument, null, textWriter); return stringBuilder.ToString(); } ... [Test] public void TransformXmlStringWithXsltString() { KoEndPoint koEndPoint = new KoEndPoint("test",null); string result = koEndPoint.TransformXmlStringWithXslString("<person name='Francis Bacon' />", "<xsl:stylesheet version='1.0' xmlns:xsl='https://www.w3.org/1999/XSL/Transform'><xsl:template match='/'>Person:<xsl:apply-templates select='*' /></xsl:template><xsl:template match='/person'><xsl:value-of select='@name' /></xsl:template></xsl:stylesheet>"); Console.Out.WriteLine("result = " + result); result.ShouldEqual("<?xml version=\"1.0\" encoding=\"utf-16\"?>Person:Francis Bacon"); }
Creates an xml doc programatically and writes to the console and a file
using System; using System.IO; using System.Xml; class CreateXMLDoc { //creates an xml doc programatically and writes to the console and a file public static void Main(string[] args) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.PrependChild(xmlDocument.CreateXmlDeclaration("1.0", "", "yes")); XmlElement element = xmlDocument.CreateElement("Book"); element.SetAttribute("author","Xenophone"); element.AppendChild(xmlDocument.CreateTextNode("The Persian Expedition")); xmlDocument.AppendChild(element); StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.Formatting = Formatting.Indented; xmlDocument.WriteTo(xmlTextWriter); xmlTextWriter.Flush(); Console.Write(stringWriter.ToString()); //get the value of the enviromental variable "TEMP" string filename = System.Environment.GetEnvironmentVariable("TEMP")+"\\Book.xml"; //write to a file in temp directory also xmlDocument.Save(filename); } }
- Convert XML to an HTML table
C# has another set of libraries
using System.Linq; using System.Text; using System.Xml.Linq; namespace SwitchBoard.Views.Handler { public class HandlerView { /// <summary> /// takes in well structured xml from something like /// SELECT * FROM mytable AS XML AUTO /// where all the elements have identical attribues /// and creates an HTML table /// </summary> /// <param name="xml">collection of xml elements all with the same attributes</param> /// <returns>HTML table with class of 'xmlTable'</returns> public string ConvertXmlToHtmlTable(string xml) { XDocument xDocument = XDocument.Parse("<outer>" + xml + "</outer>"); XElement root = xDocument.Root; if(root == null || root.Elements().Count() == 0) return "Empty"; var xmlAttributeCollection = root.Elements().First().Attributes(); StringBuilder html = new StringBuilder("<table class='xmlTable'>\r\n<tr>"); foreach (var attribute in xmlAttributeCollection) { html.Append("<th>"+attribute.Name+"</th>"); } html.Append("</tr>"); foreach (XElement element in root.Descendants()) { html.Append("\r\n<tr>"); foreach (XAttribute attrib in element.Attributes()) { html.Append("<td>"+attrib.Value+"</td>"); } html.Append("</tr>"); } html.Append("</table>"); return html.ToString(); } } }
- Get an XML document from a web service
Example of retrieving an XML document from a web service and then applying an XSLT stylesheet on the server side.
public class ScreenerQuestionsToAsk : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { GetSurveyDescriptorXMLService service = new GetSurveyDescriptorXMLService(); XmlDocument xmlDocument = service.GetAllSurveyDescriptorsAsXMLDoc(); string output = Util.WriteXMLViaXSL(xmlDocument, "w:/mydir/data/Xsl/ScreenerQuestionsToAsk.xsl"); Response.Write(output); } }
- How to write XMLNodeList to Console
public static string ToHTML(XmlNodeList xmlNodeList) { StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.Formatting = Formatting.Indented; foreach(XmlNode xmlNode in xmlNodeList) { xmlNode.WriteTo(xmlTextWriter); } return stringWriter.ToString(); }
- Returning an attribute from an XmlDocument
string total = xmlDocument.SelectSingleNode("Surveys/Survey[@name='Beer']/cellName[@name='MatureBlueCollarMen']").Attributes.GetNamedItem("total").Value;
- Using XPath
The tricky thing about getting the attribute value is using the function 'string()' inside your XPath expression. Otherwise it returns a nodeSetIterator that you have to process.
using System.Xml; using System.Xml.XPath; ... XPathDocument xPathDocument = new XPathDocument(fileName); XPathNavigator xPathNavigator = xPathDocument.CreateNavigator(); string text = (string) xPathNavigator.Evaluate("string(//Survey[@name='"+survey+"']/@URL)");
- Append a node from text into an existing DOM.
To import a new node into a DOM, we use the handy 'ImportNode()' method to avoid the 'not in document context' error.
using System.Xml; using System.Xml.XPath; ... //create initial DOM XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml("<TextDefinitions name='DataSource'></TextDefinitions>"); ... //add new node from xml text XmlDocument newXmlDocument = new XmlDocument(); newXmlDocument.LoadXml("<text lang='en-UK' name='exit'>Goodbye</text>"); XmlNode newNode = xmlDocument.ImportNode(newXmlDocument.DocumentElement,true); xmlDocument.DocumentElement.AppendChild(newNode);
- How to get a text value from a DOM using XPath.
Example C# fragment:
using System.Xml; using System.Xml.XPath; ... //create initial DOM XmlDocument xmlDocument = new XmlDocument(); /// <TextDefinitions> /// <TextDefinition name="DefaultDemographicText"> /// <Text lang="en-UK">Thanks for taking our survey.</Text> /// <Text lang="fr-FR">Merci pour prendre notre apercu.</Text> /// </TextDefinition> /// <TextDefinition name="ExitText"> /// <Text lang="en-UK">Goodbye</Text> /// <Text lang="fr-FR">Au revoir </Text> /// </TextDefinition> /// </TextDefinitions> xmlDocument.LoadXml("<TextDefinitions> <TextDefinition name='DefaultDemographicText'> <Text lang='en-UK'>Thanks for taking our survey.</Text> <Text lang='fr-FR'>Merci pour prendre notre apercu.</Text> </TextDefinition> <TextDefinition name='ExitText'> <Text lang='en-UK'>Goodbye</Text> <Text lang='fr-FR'>Au revoir </Text> </TextDefinition></TextDefinitions>"); XPathNavigator xPathNavigator = xmlDocument.CreateNavigator(); ... private string GetTextFromDOM(string textName,string lang) { string query = "string(/TextDefinitions/TextDefinition[@name='"+textName+"']/Text[@lang = '"+lang+"'])"; string text = (string) xPathNavigator.Evaluate(query); if(verbose) { Util.write("GetTextFromDOM(\""+textName+"\", \""+lang+"\"): \""+text+"\""); } return text; } }
- How to return a single node using XPath expressions with the XmlDocument
public static Survey GetSurvey(string groupName, string surveyName) { XmlDocument xmlSurveys = new XmlDocument(); xmlSurveys.Load(filename); XmlNode xmlNode = (XmlNode) xmlSurveys.SelectNodes("//Survey[@name='"+surveyName+"']").Item(0); ... }
- How to validate an xml file to a schema programatically
See also O'Reilly's Indroduction to Schemas, Microsoft's Roadmap for XML Schemas in the .NET Framework and IBM's Basics of using XML Schema.
/// <summary> /// validate an xml file to a schema /// </summary> /// <param name="xmlString">string representation of xml file</param> /// <param name="schemaString">string representation of schema</param> /// <returns>null if its happy, otherwise a string containing error messages</returns> public static string ValidateXML(string xmlString, string schemaString) { XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(xmlString)); XmlValidatingReader xmlValidatingReader = new XmlValidatingReader(xmlTextReader); xmlValidatingReader.ValidationType = ValidationType.Schema; XmlSchema xmlSchema = new XmlSchema(); xmlSchema = XmlSchema.Read(new StringReader(schemaString),null); xmlValidatingReader.Schemas.Add(xmlSchema); Validate validate = new Validate(); ValidationEventHandler validationEventHandler = new ValidationEventHandler(validate.Validator); xmlValidatingReader.ValidationEventHandler += validationEventHandler; while (xmlValidatingReader.Read()); return validate.errors; } /// <summary> /// tiny class so we can have a ValidationEventHandler and collect the errors /// </summary> private class Validate { public string errors = null; public void Validator(object sender, ValidationEventArgs args) { errors += args.Message + "\r\n"; } }
- Creating a DOM programmatically
[Test] new public void GenerateVenues() { writeMethodStart(MethodInfo.GetCurrentMethod().ToString()); XmlDocument xdoc = new XmlDocument(); XmlElement root = xdoc.CreateElement("Schedule"); xdoc.AppendChild(root); XmlElement day = xdoc.CreateElement("Day"); XmlAttribute date = xdoc.CreateAttribute("date"); date.Value = "2004/01/01"; day.SetAttributeNode(date); XmlAttribute num = xdoc.CreateAttribute("number"); num.Value = "5"; day.SetAttributeNode(num); root.AppendChild(day); write(To.ToText(xdoc)); writeMethodEnd(); }
This produces:
<Schedule> <Day date="2004/01/01" number="5" /> </Schedule>
- Example of Serialization using the Xml Formatter
The binary and SOAP formatters are more useful in most situations.
using System; using System.Xml; using System.Xml.Serialization; using System.IO; public class SerializeExample { [Serializable] public class Employee { public string name; public int yearOfBirth; public Employee(string name, int yearOfBirth) { this.name = name; this.yearOfBirth = yearOfBirth; } public Employee() {} //needed for serialization } public static void Main(string[] args) { Console.Write("starting serialization..."); FileStream fileStream = File.Create("SerializeExample.xml"); XmlSerializer xmlSerializer = new XmlSerializer(typeof(Employee),"Employee"); xmlSerializer.Serialize(fileStream,new Employee("Achilles",1972)); fileStream.Close(); Console.Write("done."); } }
Contents of the file:
<?xml version="1.0"?> <Employee xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="Employee"> <name>Achilles</name> <yearOfBirth>1972</yearOfBirth> </Employee>
- Playing with XML
Write a very simple XML fragment the hard way.
static void writeTree(XmlNode xmlElement, int level) { String levelDepth = ""; for(int i=0;i<level;i++) { levelDepth += " "; } Console.Write("\n{0}<{1}",levelDepth,xmlElement.Name); XmlAttributeCollection xmlAttributeCollection = xmlElement.Attributes; foreach(XmlAttribute x in xmlAttributeCollection) { Console.Write(" {0}='{1}'",x.Name,x.Value); } Console.Write(">"); XmlNodeList xmlNodeList = xmlElement.ChildNodes; ++level; foreach(XmlNode x in xmlNodeList) { if(x.NodeType == XmlNodeType.Element) { writeTree((XmlNode)x, level); } else if(x.NodeType == XmlNodeType.Text) { Console.Write("\n{0} {1}",levelDepth,(x.Value).Trim()); } } Console.Write("\n{0}</{1}>",levelDepth,xmlElement.Name); }
- Write a very simple XML fragment the easier way
StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.Formatting = Formatting.Indented; xmlDocument.WriteTo(xmlTextWriter); //xmlDocument can be replaced with an XmlNode xmlTextWriter.Flush(); Console.Write(stringWriter.ToString());
- To write any object or some collections to xml
Object must have a default constructor.
public static string SerializeToXmlString(object objectToSerialize) { MemoryStream memoryStream = new MemoryStream(); System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(objectToSerialize.GetType()); xmlSerializer.Serialize(memoryStream, objectToSerialize); ASCIIEncoding ascii = new ASCIIEncoding(); return ascii.GetString(memoryStream.ToArray()); }
- And this should turn the xml back into an object
public static object DeSerializeFromXmlString(System.Type typeToDeserialize, string xmlString) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(xmlString); MemoryStream memoryStream = new MemoryStream(bytes); System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeToDeserialize); return xmlSerializer.Deserialize(memoryStream); }
Example
[Test] public void GetBigList() { var textRepository = ObjectFactory.GetInstance<ITextRepository>(); List<BrandAndCode> brandAndCodeList = textRepository.GetList(...); string xml = SerializeToXmlString(brandAndCodeList); Console.Out.WriteLine("xml = {0}", xml); var brandAndCodeList2 = DeSerializeFromXmlString(typeof (BrandAndCode[]), xml); }