This is the third part of the SQLxD series. For your convenience you can find other parts in the table of contents in Part 1 – XML Transformation
We want to represent nodes in the following way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
using System; using System.Collections.Generic; using System.Linq; namespace Model { public class Node : IEquatable<Node> { public IEnumerable<Node> InnerNodes; public Node() { Value = null; InnerNodes = new List<Node>(); Guid = Guid.NewGuid(); } public NodeType Type { get; set; } public string Value { get; set; } public string Name { get; set; } public Node Parent { get; set; } public Guid Guid { get; private set; } public bool Equals(Node other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return InnerNodes.SequenceEqual(other.InnerNodes) && Type == other.Type && string.Equals(Value, other.Value) && string.Equals(Name, other.Name); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((Node)obj); } public override int GetHashCode() { unchecked { int hashCode = (InnerNodes != null ? InnerNodes.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (int)Type; hashCode = (hashCode * 397) ^ (Value != null ? Value.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Parent != null ? Parent.GetHashCode() : 0); return hashCode; } } } } |
Node has its type, name, pointer to parent, and identifier. Type is one of these:
1 2 3 4 5 6 7 8 9 10 |
namespace Model { public enum NodeType { Invalid, Element, Attribute, Text } } |
Now we can parse the document:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using Model; namespace Parser { public static class XmlDocumentParser { public static Node Parse(string xml) { XDocument document = XDocument.Parse(xml); return ParseDocument(document); } private static Node ParseDocument(XDocument document) { XElement rootNode = document.Root; if (rootNode == null) { return null; } Node result = ParseElement(rootNode); FixParents(result); return result; } private static Node ParseElement(XElement rootNode) { var result = new Node { Name = rootNode.Name.LocalName, Value = ParseNodeTextValue(rootNode), InnerNodes = ParseInnerNodes(rootNode), Type = NodeType.Element, }; return result; } private static string ParseNodeTextValue(XElement element) { return GetOneLevelValue(element); } private static string GetOneLevelValue(XElement element) { return string.Concat(element.Nodes().OfType<XText>().Select(t => t.Value)); } private static IEnumerable<Node> ParseInnerNodes(XElement element) { return new List<Node> { ParseNodeTextValueAsNode(element) }.Concat(ParseAttributes(element)) .Concat(ParseChilds(element)).ToArray(); } private static Node ParseNodeTextValueAsNode(XElement element) { return new Node { Name = "#", Value = ParseNodeTextValue(element), Type = NodeType.Text, }; } private static IEnumerable<Node> ParseAttributes(XElement element) { return element.Attributes().Select(ParseSingleAttribute); } private static Node ParseSingleAttribute(XAttribute attribute) { return new Node { Name = attribute.Name.LocalName, Value = attribute.Value, Type = NodeType.Attribute, InnerNodes = new List<Node> { new Node { Name = "#", Value = attribute.Value, Type = NodeType.Text, } } }; } private static IEnumerable<Node> ParseChilds(XElement element) { return element.Elements().Select(ParseElement); } private static void FixParents(Node parent) { foreach (Node child in parent.InnerNodes) { child.Parent = parent; FixParents(child); } } } } |
We simply traverse whole document and create nodes for every XML node.