/Utilities/Xml/XmlHelper.cs
C# | 586 lines | 355 code | 38 blank | 193 comment | 20 complexity | df38d8aa24c81214118ad42b56556587 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.IO;
- using System.Xml;
- using System.Xml.Serialization;
- using Delta.Utilities.Helpers;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Xml
- {
- /// <summary>
- /// Xml helper class to provide some helper functionality for extracting or
- /// generating xml data from XmlNodes.
- /// </summary>
- public class XmlHelper
- {
- #region Serialize (Static)
- /// <summary>
- /// Serializes an object
- /// This saves an object as an xml structure to a file.
- /// Every variable is saved as a node with
- /// </summary>
- /// <param name="filePath">filepath</param>
- /// <param name="obj">obj</param>
- public static void Serialize(string filePath, object obj)
- {
- using (FileStream stream = FileHelper.Open(filePath,
- FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
- {
- StreamWriter fileWriter = new StreamWriter(stream);
- // create an Serializer with the objects type so it'll
- // know what to serialize
- XmlSerializer xmls = new XmlSerializer(obj.GetType());
- // create an XmlWriter which will save the data to the file
- XmlWriter writer = XmlWriter.Create(fileWriter);
- // serialize the object we got as parameter and write it to the
- // stream of the above created Xmlwriter.
- xmls.Serialize(writer, obj);
- // will be called automatically by the "using" block
- //// Close the writer so the file isn't locked by the writer any more
- ////writer.Close();
- }
- }
- #endregion
-
- #region Deserialize (Static)
- /// <summary>
- /// Deserialize a file to an object
- /// This reads an xml structured file if it's of the same type
- /// as we provide in the parameters
- /// It returns an object by the type we declared and we can
- /// simply cast the object after calling this function
- /// </summary>
- /// <param name="fileName">filename</param>
- /// <param name="type">type</param>
- /// <returns>Deserialized object</returns>
- public static object Deserialize(string fileName, Type type)
- {
- // create a Serializer which knows how to handle the type we
- // give the constructor
- XmlSerializer xmls = new XmlSerializer(type);
- object obj = null;
- using (FileStream stream = FileHelper.Open(fileName,
- FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- {
- // create an XmlReader that can read the xml file at fileName
- XmlReader reader = XmlReader.Create(stream);
- // deserialize the data in the xml file and return an object that is of
- // the type we provided, or null if the file is not of the provided type.
- // The Deserialisation process reads the nodes from the file,
- // creates an instance of the type and saves the values from the file
- // to the objects variables
- obj = xmls.Deserialize(reader);
- }
- // return our object (null if something went wrong)
- return obj;
- }
- #endregion
-
- #region AddDeclaration (Static)
- /// <summary>
- /// Add an xml declaration
- /// </summary>
- /// <param name="version">The current version of the xml file.</param>
- /// <param name="encoding">The current encoding of the xml file.</param>
- /// <returns>xml declaration</returns>
- public static string AddDeclaration(string version, string encoding)
- {
- return "<?xml version=\"" + version + "\" encoding=\"" + encoding +
- "\"?>";
- }
- #endregion
-
- #region AddTag (Static)
- /// <summary>
- /// Create a tag item from the specified string.
- /// </summary>
- /// <param name="tagName">The name of the tag to create.</param>
- /// <returns>string</returns>
- public static string AddTag(string tagName)
- {
- return "<" + tagName + ">";
- }
-
- /// <summary>
- /// Add a tag with a given depth
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>Tag with given depth</returns>
- public static string AddTag(string tagName, int depth)
- {
- string xmlNode = "";
- for (int i = 0; i < depth; i++)
- {
- xmlNode += " ";
- }
- return xmlNode += AddTag(tagName);
- }
- #endregion
-
- #region AddTagEnd (Static)
- /// <summary>
- /// Add a tag end
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <returns>tag</returns>
- public static string AddTagEnd(string tagName)
- {
- return "</" + tagName + ">";
- }
-
- /// <summary>
- /// Add a tag end with a given depth
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>tag</returns>
- public static string AddTagEnd(string tagName, int depth)
- {
- string xmlNode = "";
- for (int i = 0; i < depth; i++)
- {
- xmlNode += " ";
- }
- return xmlNode += AddTagEnd(tagName);
- }
- #endregion
-
- #region AddElement (Static)
- /// <summary>
- /// Add an element
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="element">Element</param>
- /// <returns>string</returns>
- public static string AddElement(string tagName, string element)
- {
- return "<" + tagName + ">" + element + "</" + tagName + ">";
- }
-
- /// <summary>
- /// Add an element
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="element">Element</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>string</returns>
- public static string AddElement(string tagName, string element, int depth)
- {
- return new string(' ', depth * 2) +
- AddElement(tagName, element);
- }
- #endregion
-
- #region AddAttribute (Static)
- /// <summary>
- /// Add an attribute. The number of attribute names and values must be
- /// equal. Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <returns>xmlNode</returns>
- public static string AddAttribute(string tagName, string[] attributeNames,
- string[] attributeValues)
- {
- // Check if every attribute name has a value or vice versa
- if (attributeNames.Length !=
- attributeValues.Length)
- {
- // Return an empty element if this is not the case.
- return AddTag(tagName) + AddTagEnd(tagName);
- }
-
- // Start adding the attributes and their values.
- string xmlNode = "<" + tagName;
- for (int i = 0; i < attributeNames.Length; i++)
- {
- xmlNode += " " + attributeNames[i] + "=\"" + attributeValues[i] + "\"";
- }
- return xmlNode += ">";
- }
-
- /// <summary>
- /// Add an attribute with a given depth. The number of attribute names and
- /// values must be equal.
- /// Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>string</returns>
- public static string AddAttribute(string tagName, string[] attributeNames,
- string[] attributeValues, int depth)
- {
- return new string(' ', depth * 2) +
- AddAttribute(tagName, attributeNames, attributeValues);
- }
- #endregion
-
- #region AddAttributeEnd (Static)
- /// <summary>
- /// Add an attribute with an end. The number of attribute names and values
- /// must be equal.
- /// Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <returns>String with the new xmlNode data</returns>
- public static string AddAttributeEnd(string tagName,
- string[] attributeNames, string[] attributeValues)
- {
- // Check if every attribute name has a value or vice versa
- if (attributeNames.Length !=
- attributeValues.Length)
- {
- // Return an empty element if this is not the case.
- return AddTag(tagName) + AddTagEnd(tagName);
- }
-
- // Start adding the attributes and their values.
- string xmlNode = "<" + tagName;
- for (int i = 0; i < attributeNames.Length; i++)
- {
- xmlNode += " " + attributeNames[i] + "=\"" + attributeValues[i] + "\"";
- }
- return xmlNode += "/>";
- }
-
- /// <summary>
- /// Add an attribute with a given depth and an end. The number of
- /// attribute names and values must be equal.
- /// Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>string</returns>
- public static string AddAttributeEnd(string tagName,
- string[] attributeNames, string[] attributeValues, int depth)
- {
- return new string(' ', depth * 2) +
- AddAttributeEnd(tagName, attributeNames, attributeValues);
- }
- #endregion
-
- #region AddAttributeElement (Static)
- /// <summary>
- /// Add an attribute with a given element between the start and end tag.
- /// The number of attribute names and values must be equal.
- /// Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <param name="element">Element</param>
- /// <returns>string</returns>
- public static string AddAttributeElement(string tagName,
- string[] attributeNames, string[] attributeValues, string element)
- {
- // Check if every attribute name has a value or vice versa
- if (attributeNames.Length !=
- attributeValues.Length)
- {
- // Return an empty element if this is not the case.
- return AddTag(tagName) + AddTagEnd(tagName);
- }
-
- // Start adding the attributes and their values.
- string xmlNode = "<" + tagName;
- for (int i = 0; i < attributeNames.Length; i++)
- {
- xmlNode += " " + attributeNames[i] + "=\"" + attributeValues[i] + "\"";
- }
- if (String.IsNullOrEmpty(element))
- {
- return xmlNode += "/>";
- }
- else
- {
- return xmlNode += ">" + element + AddTagEnd(tagName);
- }
- }
-
- /// <summary>
- /// Add an attribute with a given element between the start and end tag and
- /// a given depth.
- /// The number of attribute names and values must be equal.
- /// Each value will be assigned to a name with the corresponding
- /// position in the arrays. (1="1" , 2="2", ...)
- /// </summary>
- /// <param name="tagName">Tag name</param>
- /// <param name="attributeNames">Attribute names</param>
- /// <param name="attributeValues">Attribute values</param>
- /// <param name="element">Element</param>
- /// <param name="depth">Depth of the node</param>
- /// <returns>string</returns>
- public static string AddAttributeElement(string tagName,
- string[] attributeNames, string[] attributeValues, string element,
- int depth)
- {
- return new string(' ', depth * 2) +
- AddAttributeElement(tagName, attributeNames, attributeValues, element);
- }
- #endregion
-
- #region ConvertToXmlSpecialCharacters (Static)
- /// <summary>
- /// Convert to xml special characters, will replace all special characters
- /// that need replacement (< becomes <, " becomes ", etc.).
- /// See http://xml.silmaril.ie/authors/specials/ for more information.
- /// Note: The input text should not already contain special xml characters.
- /// </summary>
- /// <param name="inputText">input text</param>
- /// <returns>string</returns>
- public static string ConvertToXmlSpecialCharacters(string inputText)
- {
- #region Replace '&'
- // We have to check this differently, because it can be an '&' of a
- // special character which would result in an '&lt;' for '<'.
-
- int[] ampIndices = inputText.GetAllIndicesOf("&");
- for (int index = ampIndices.Length - 1; index >= 0; index--)
- {
- string checkString = inputText.Substring(ampIndices[index]);
- if (checkString.StartsWith("&") ||
- checkString.StartsWith("<") ||
- checkString.StartsWith(">") ||
- checkString.StartsWith(""") ||
- checkString.StartsWith("'"))
- {
- continue;
- }
-
- inputText = inputText.Insert(ampIndices[index] + 1, "amp;");
- }
- #endregion
-
- return inputText.
- Replace("<", "<").
- Replace(">", ">").
- Replace("\"", """).
- Replace("'", "'");
- }
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class XmlHelperTests
- {
- #region Helpers
- private const string TestXmlDocumentPath =
- @"C:\Windows\System32\icsxml\ipcfg.xml";
- #endregion
-
- #region LoadFile (Static)
- /// <summary>
- /// Load file. Note: Too slow for a dynamic unit test.
- /// </summary>
- [Test]
- public static void LoadFile()
- {
- Assert.NotNull(XmlNode.FromFile(TestXmlDocumentPath));
- }
- #endregion
-
- #region LoadingMultipleXmlFiles (Static)
- /// <summary>
- /// Loading multiple xml files. Note: Too slow for dynamic unit tests
- /// </summary>
- [Test]
- public static void LoadingMultipleXmlFiles()
- {
- const int TestRuns = 10;
- for (int i = 0; i < TestRuns; i++)
- {
- XmlNode.FromFile(TestXmlDocumentPath);
- //XmlHelper.LoadXmlFromFile("");
- }
- }
- #endregion
-
- #region TestSerialization (Static)
- /// <summary>
- /// Test serialization. Note: This test is too slow for a dynamic unit
- /// test. It also is strange that this c:\testfile.xml is created ..
- /// </summary>
- [Test]
- public static void TestSerialization()
- {
- string teststring = "This is a test string for Serialization";
- Serialize("testfile.xml", teststring);
- Assert.True(File.Exists("testfile.xml"),
- "Check if file exists (indicates that serialization worked)");
- object checkObject = Deserialize("testfile.xml",
- typeof(string));
- Assert.Equal(teststring, (string)checkObject);
- FileHelper.SafeDelete("testfile.xml");
- }
- #endregion
-
- #region XmlGeneration (Static)
- /// <summary>
- /// XmlGeneration
- /// </summary>
- [Test]
- public static void XmlGeneration()
- {
- FileStream saveHandle = FileHelper.Open("Unit-Test.xml",
- FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
-
- using (StreamWriter stream = new StreamWriter(saveHandle))
- {
- stream.WriteLine(AddDeclaration("1.0", "utf-8"));
- stream.WriteLine(AddAttribute("COLLADA",
- new[]
- {
- "xmlns", "version"
- },
- new[]
- {
- "http://www.collada.org/2005/11/COLLADASchema",
- "1.4.1"
- }));
- stream.WriteLine(AddTag("asset", 1));
- stream.WriteLine(AddTag("contributor", 2));
- stream.WriteLine(AddElement("author", "Kevin", 3));
- stream.WriteLine(AddTagEnd("contributor", 2));
- stream.WriteLine(AddAttributeEnd("unit",
- new[]
- {
- "meter", "name"
- },
- new[]
- {
- "0.0254", "inch"
- }, 2));
- stream.WriteLine(AddAttributeElement("positions",
- new[]
- {
- "id", "type"
- },
- new[]
- {
- "x", "element"
- },
- "0 1 2 3 4 5 6 7 8 9 10", 2));
- stream.WriteLine(AddTagEnd("asset", 1));
- stream.WriteLine(AddTagEnd("COLLADA"));
- }
-
- Log.Test("File created successfully");
- }
- #endregion
-
- #region ImportFromXml (Static)
- /// <summary>
- /// Import from xml
- /// </summary>
- [Test]
- public static void ImportFromXml()
- {
- XmlNode workbook = XmlNode.FromFile(@"Enemy Stats.xml");
- if (workbook == null)
- {
- return;
- }
-
- Log.Test("Importing SportPlacesGermany.xml");
- // Get all worksheets (we have many)
- foreach (XmlNode worksheet in workbook.Children)
- {
- if (worksheet.Name == "Worksheet")
- {
- string tableName = worksheet.GetAttribute("Name", false);
- Log.Test("Importing table: " + tableName);
-
- // Get the inside table with all the data
- XmlNode table = worksheet.GetChild("Table");
- // And iterate through all rows
- foreach (XmlNode row in table.Children)
- {
- if (row.Name == "Row")
- {
- // Grab all values that could be interesting for us
- foreach (XmlNode cell in row.Children)
- {
- XmlNode data = cell.GetChild("Data");
- if (data != null)
- {
- Console.Write(data.Value + " ");
- }
- }
- }
- }
- }
- }
- }
- #endregion
-
- #region LoadSnippet
- /// <summary>
- /// Load snippet
- /// </summary>
- [Test]
- public void LoadSnippet()
- {
- string xmlSnippet =
- @"
- <Root>
- <Child>
- <SubChild1>1</SubChild1>
- <SubChild2>2</SubChild2>
- </Child>
- </Root>
- ";
-
- XmlNode rootNode = XmlNode.FromSnippet(xmlSnippet);
- Assert.NotNull(rootNode);
- Assert.Equal("Root", rootNode.Name);
- Assert.Equal(1, rootNode.Children.Length);
-
- XmlNode childNode = rootNode.Children[0];
- Assert.Equal("Child", childNode.Name);
- Assert.Equal(2, childNode.Children.Length);
-
- XmlNode subChild1 = childNode.Children[0];
- Assert.Equal(0, subChild1.Children.Length);
- Assert.Equal("SubChild1", subChild1.Name);
- Assert.Equal("1", subChild1.Value);
-
- XmlNode subChild2 = childNode.Children[1];
- Assert.Equal(0, subChild2.Children.Length);
- Assert.Equal("SubChild2", subChild2.Name);
- Assert.Equal("2", subChild2.Value);
- }
- #endregion
-
- #region ConvertToXmlSpecialCharacters
- /// <summary>
- /// Convert to xml special characters
- /// </summary>
- [Test]
- public void ConvertToXmlSpecialCharacters()
- {
- Assert.Equal("Hello",
- XmlHelper.ConvertToXmlSpecialCharacters("Hello"));
- Assert.Equal("<", XmlHelper.ConvertToXmlSpecialCharacters("<"));
- Assert.Equal(">", XmlHelper.ConvertToXmlSpecialCharacters(">"));
- Assert.Equal(""&"",
- XmlHelper.ConvertToXmlSpecialCharacters("\"&\""));
- Assert.Equal("'", XmlHelper.ConvertToXmlSpecialCharacters("'"));
- }
- #endregion
- }
- }
- }