/* INFINITY CODE 2013-2019 */ /* http://www.infinity-code.com */ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using InfinityCode.RealWorldTerrain.Utils; using UnityEngine; using Object = UnityEngine.Object; #if NETFX_CORE using Windows.Data.Xml.Dom; #else using System.Xml; #endif namespace InfinityCode.RealWorldTerrain.XML { /// /// Wrapper for XML. /// public class RealWorldTerrainXML : IEnumerable { private XmlDocument _document; private XmlElement _element; /// /// Name of the node. /// public string name { #if !NETFX_CORE get { return _element != null ? _element.Name : null; } #else get { return _element != null ? _element.TagName: null; } #endif } /// /// The number of child nodes. /// public int count { get { return hasChildNodes ? _element.ChildNodes.Count : 0; } } /// /// Checks whether the contents of the node. /// public bool isNull { get { return _document == null || _element == null; } } /// /// Reference to XmlDocument. /// public XmlDocument document { get { return _document; } } /// /// Reference to XmlElement. /// public XmlElement element { get { return _element; } } /// /// Gets a value indicating whether the current node has any attributes. /// public bool hasAttributes { get { return _element != null && _element.Attributes.Count > 0; } } /// /// Gets a value indicating the presence of the child nodes from the current node. /// public bool hasChildNodes { get { #if !NETFX_CORE return _element != null && _element.HasChildNodes; #else return _element != null && _element.HasChildNodes(); #endif } } /// /// Content of node as string. /// public string outerXml { get { #if !NETFX_CORE return _element != null ? _element.OuterXml : null; #else return _element != null? _element.GetXml(): null; #endif } } /// /// Get the child element by index. /// /// Index of child element. /// Child element. public RealWorldTerrainXML this[int index] { get { if (!hasChildNodes) return new RealWorldTerrainXML(); if (index < 0 || index >= _element.ChildNodes.Count) return new RealWorldTerrainXML(); return new RealWorldTerrainXML(_element.ChildNodes[index] as XmlElement); } } /// /// Get the child element by name. /// /// Name of child element. /// Child element. public RealWorldTerrainXML this[string childName] { get { if (!hasChildNodes) return new RealWorldTerrainXML(); #if !NETFX_CORE return new RealWorldTerrainXML(_element[childName]); #else return new RealWorldTerrainXML(GetFirstChild(_element, childName)); #endif } } /// /// Creates an empty element. /// public RealWorldTerrainXML() { } /// /// Creates a new element with the specified name. /// /// Name of element. public RealWorldTerrainXML(string nodeName) { try { _document = new XmlDocument(); _element = _document.CreateElement(nodeName); _document.AppendChild(_element); } catch (Exception) { _document = null; _element = null; } } /// /// Creates a new element based on the XmlElement. /// /// XmlElement for which will create the wrapper. public RealWorldTerrainXML(XmlElement xmlElement) { if (xmlElement == null) return; _element = xmlElement; _document = _element.OwnerDocument; } /// /// Get an attribute by name. /// /// Name of attribute. /// Value of attribute as string. public string A(string attributeName) { return A(attributeName); } /// /// Get an attribute by name, and return as the specified type. /// /// Type of attribute. /// Name of attribute. /// Value of attribute as specified type. public T A(string attributeName) { if (!hasAttributes) return default(T); #if !NETFX_CORE XmlAttribute el = _element.Attributes[attributeName]; #else XmlAttribute el = _element.Attributes.GetNamedItem(attributeName) as XmlAttribute; #endif if (el == null) return default(T); string value = el.Value; if (string.IsNullOrEmpty(value)) return default(T); Type type = typeof(T); if (type == typeof(string)) return (T) Convert.ChangeType(value, type); T obj = default(T); PropertyInfo[] properties = RealWorldTerrainReflectionHelper.GetProperties(type); Type underlyingType = type; #if !UNITY_WSA if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.InvariantCultureIgnoreCase)) underlyingType = properties[1].PropertyType; #else if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.OrdinalIgnoreCase)) underlyingType = properties[1].PropertyType; #endif MethodInfo method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string), typeof(IFormatProvider) }); if (method != null) return (T)method.Invoke(null, new object[] { value, RealWorldTerrainCultureInfo.numberFormat }); method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string) }); if (method != null) return (T)method.Invoke(null, new[] { value }); return obj; } /// /// Set an named attribute. /// /// Name of attribute. /// Value of attribute. public void A(string attributeName, object value) { if (_element == null) return; _element.SetAttribute(attributeName, value.ToString()); } /// /// Sets the color attribute as hex value. /// /// Name of attribute. /// Color public void A(string attributeName, Color32 value) { A(attributeName, value.r.ToString("X2") + value.g.ToString("X2") + value.b.ToString("X2")); } /// /// Append a child element. /// /// Element. public void AppendChild(XmlElement newChild) { if (_element == null || newChild == null) return; if (_element.OwnerDocument != newChild.OwnerDocument) newChild = _element.OwnerDocument.ImportNode(newChild, true) as XmlElement; _element.AppendChild(newChild); } /// /// Append a child element. /// /// Element. public void AppendChild(RealWorldTerrainXML newChild) { if (newChild == null) return; AppendChild(newChild._element); } /// /// Append a child elements. /// /// List of elements. #if !NETFX_CORE public void AppendChilds(IEnumerable list) #else public void AppendChilds(IEnumerable list) #endif { if (_element == null) return; foreach (var node in list) _element.AppendChild(node); } /// /// Append a child elements. /// /// List of elements. public void AppendChilds(IEnumerable list) { if (_element == null) return; foreach (RealWorldTerrainXML node in list) { if (node._element != null) _element.AppendChild(node._element); } } /// /// Append a child elements. /// /// List of elements. public void AppendChilds(XmlNodeList list) { if (_element == null) return; #if !NETFX_CORE foreach (XmlNode node in list) _element.AppendChild(node); #else foreach (IXmlNode node in list) _element.AppendChild(node); #endif } /// /// Append a child elements. /// /// List of elements. public void AppendChilds(RealWorldTerrainXMLList list) { if (_element == null) return; foreach (RealWorldTerrainXML node in list) { if (node._element != null) _element.AppendChild(node._element); } } /// /// Creates a child element with the specified name. /// /// Name of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName) { if (_document == null || _element == null) return new RealWorldTerrainXML(); XmlElement xmlElement = _document.CreateElement(nodeName); _element.AppendChild(xmlElement); return new RealWorldTerrainXML(xmlElement); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, bool value) { return Create(nodeName, value ? "True" : "False"); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, Color32 value) { return Create(nodeName, value.r.ToString("X2") + value.g.ToString("X2") + value.b.ToString("X2")); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, float value) { return Create(nodeName, value.ToString()); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, double value) { return Create(nodeName, value.ToString()); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, int value) { return Create(nodeName, value.ToString()); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, Object value) { return Create(nodeName, value != null ? value.GetInstanceID() : 0); } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, string value) { RealWorldTerrainXML node = Create(nodeName); node.SetChild(value); return node; } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, Vector2 value) { RealWorldTerrainXML node = Create(nodeName); node.Create("X", value.x); node.Create("Y", value.y); return node; } /// /// Creates a child element with the specified name and value. /// /// Name of child element. /// Value of child element. /// Child element. public RealWorldTerrainXML Create(string nodeName, Vector3 value) { RealWorldTerrainXML node = Create(nodeName); node.Create("X", value.x); node.Create("Y", value.y); node.Create("Z", value.z); return node; } /// /// Find a child at the specified XPath. /// /// XPath string. /// An XmlNamespaceManager to use for resolving namespaces for prefixes in the XPath expression. /// Child element. public RealWorldTerrainXML Find(string xpath, System.Xml.XmlNamespaceManager nsmgr = null) { if (!hasChildNodes) return new RealWorldTerrainXML(); #if !NETFX_CORE XmlElement xmlElement = _element.SelectSingleNode(xpath, nsmgr) as XmlElement; #else string ns = null; if (nsmgr != null) { var nss = nsmgr.GetNamespacesInScope(System.Xml.XmlNamespaceScope.ExcludeXml); if (nss.Keys.Count > 0) { var key = nss.Keys.First(); ns = String.Format("xmlns:{0}='{1}'", key, nsmgr.LookupNamespace(key)); } } XmlElement xmlElement = (ns == null ? _element.SelectSingleNode(xpath) : _element.SelectSingleNodeNS(xpath, ns)) as XmlElement; #endif if (xmlElement != null) return new RealWorldTerrainXML(xmlElement); return new RealWorldTerrainXML(); } /// /// Find a child at the specified XPath, and return value as the specified type. /// /// Type of child element. /// XPath string. /// An XmlNamespaceManager to use for resolving namespaces for prefixes in the XPath expression. /// Value of child element as the specified type. public T Find(string xpath, System.Xml.XmlNamespaceManager nsmgr = null) { if (!hasChildNodes) return default(T); #if !NETFX_CORE return Get(_element.SelectSingleNode(xpath, nsmgr) as XmlElement); #else string ns = null; if (nsmgr != null) { var nss = nsmgr.GetNamespacesInScope(System.Xml.XmlNamespaceScope.ExcludeXml); if (nss.Keys.Count > 0) { var key = nss.Keys.First(); ns = String.Format("xmlns:{0}='{1}'", key, nsmgr.LookupNamespace(key)); } } return Get((ns == null ? _element.SelectSingleNode(xpath) : _element.SelectSingleNodeNS(xpath, ns)) as XmlElement); #endif } /// /// Finds all childs at the specified XPath. /// /// XPath string. /// An XmlNamespaceManager to use for resolving namespaces for prefixes in the XPath expression. /// List of the elements. public RealWorldTerrainXMLList FindAll(string xpath, System.Xml.XmlNamespaceManager nsmgr = null) { if (!hasChildNodes) return new RealWorldTerrainXMLList(); #if !NETFX_CORE return new RealWorldTerrainXMLList(_element.SelectNodes(xpath, nsmgr)); #else string ns = null; if (nsmgr != null) { var nss = nsmgr.GetNamespacesInScope(System.Xml.XmlNamespaceScope.ExcludeXml); if (nss.Keys.Count > 0) { var key = nss.Keys.First(); ns = String.Format("xmlns:{0}='{1}'", key, nsmgr.LookupNamespace(key)); } } return new RealWorldTerrainXMLList(ns == null ? _element.SelectNodes(xpath) : _element.SelectNodesNS(xpath, ns)); #endif } /// /// Get the value of element as string. /// /// Name of child. /// Value of element as string. public string Get(string childName) { return Get(childName); } #if NETFX_CORE private static XmlElement GetFirstChild(XmlElement element, string childName) { if (element == null) return null; var nodeList = element.GetElementsByTagName(childName); if (nodeList.Count == 0) return null; return nodeList[0] as XmlElement; } #endif /// /// Get the value of element as the specified type. /// /// Type of element /// Element /// Value of element as the specified type. public T Get(XmlElement el) { if (el == null) return default(T); #if !NETFX_CORE string value = el.InnerXml; #else string value = el.InnerText; #endif if (string.IsNullOrEmpty(value)) return default(T); Type type = typeof(T); if (type == typeof(string)) return (T) Convert.ChangeType(value, type); if (type == typeof(Color) || type == typeof(Color32)) return (T) Convert.ChangeType(RealWorldTerrainUtils.HexToColor(value), type); #if !NETFX_CORE if (type == typeof(Vector2)) return (T) Convert.ChangeType(new Vector2(Get(el["X"]), Get(el["Y"])), type); if (type == typeof(Vector3)) return (T) Convert.ChangeType(new Vector3(Get(el["X"]), Get(el["Y"]), Get(el["Z"])), type); #else if (type == typeof(Vector2)) return (T)Convert.ChangeType(new Vector2(Get(GetFirstChild(el, "X")), Get(GetFirstChild(el, "Y"))), type); if (type == typeof(Vector3)) return (T)Convert.ChangeType(new Vector3(Get(GetFirstChild(el, "X")), Get(GetFirstChild(el, "Y")), Get(GetFirstChild(el, "Z"))), type); #endif T obj = default(T); PropertyInfo[] properties = RealWorldTerrainReflectionHelper.GetProperties(type); Type underlyingType = type; #if !UNITY_WSA if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.InvariantCultureIgnoreCase)) underlyingType = properties[1].PropertyType; #else if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.OrdinalIgnoreCase)) underlyingType = properties[1].PropertyType; #endif try { MethodInfo method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string), typeof(IFormatProvider) }); if (method != null) obj = (T)method.Invoke(null, new object[] { value, RealWorldTerrainCultureInfo.numberFormat }); else { method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string) }); obj = (T)method.Invoke(null, new[] { value }); } } catch (Exception exception) { Debug.Log(exception.Message + "\n" + exception.StackTrace); throw; } return obj; } /// /// Get the value of element as the specified type or default value if the child is not found. /// /// Type of element /// Element /// Default value /// Value of element as the specified type or default value. public T Get(XmlElement el, T defaultValue) { if (el == null) return defaultValue; #if !NETFX_CORE string value = el.InnerXml; #else string value = el.InnerText; #endif if (string.IsNullOrEmpty(value)) return defaultValue; Type type = typeof(T); if (type == typeof(string)) return (T) Convert.ChangeType(value, type); if (type == typeof(Color) || type == typeof(Color32)) return (T) Convert.ChangeType(RealWorldTerrainUtils.HexToColor(value), type); #if !NETFX_CORE if (type == typeof(Vector2)) return (T) Convert.ChangeType(new Vector2(Get(el["X"]), Get(el["Y"])), type); if (type == typeof(Vector3)) return (T) Convert.ChangeType(new Vector3(Get(el["X"]), Get(el["Y"]), Get(el["Z"])), type); #else if (type == typeof(Vector2)) return (T)Convert.ChangeType(new Vector2(Get(GetFirstChild(el, "X")), Get(GetFirstChild(el, "Y"))), type); if (type == typeof(Vector3)) return (T)Convert.ChangeType(new Vector3(Get(GetFirstChild(el, "X")), Get(GetFirstChild(el, "Y")), Get(GetFirstChild(el, "Z"))), type); #endif T obj = defaultValue; PropertyInfo[] properties = RealWorldTerrainReflectionHelper.GetProperties(type); Type underlyingType = type; #if !UNITY_WSA if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.InvariantCultureIgnoreCase)) underlyingType = properties[1].PropertyType; #else if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.OrdinalIgnoreCase)) underlyingType = properties[1].PropertyType; #endif try { MethodInfo method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string), typeof(IFormatProvider) }); if (method != null) obj = (T)method.Invoke(null, new object[] { value, RealWorldTerrainCultureInfo.numberFormat }); else { method = RealWorldTerrainReflectionHelper.GetMethod(underlyingType, "Parse", new[] { typeof(string) }); obj = (T)method.Invoke(null, new[] { value }); } } catch (Exception exception) { Debug.Log(exception.Message + "\n" + exception.StackTrace); throw; } return obj; } /// /// Get the value of child element as the specified type. /// /// Type of child element. /// Name of child. /// Value of element as the specified type. public T Get(string childName) { if (!hasChildNodes) return default(T); #if !NETFX_CORE return Get(_element[childName]); #else return Get(GetFirstChild(_element, childName)); #endif } /// /// Get the value of child element as the specified type or default value if the child is not found. /// /// Type of child element. /// Name of child. /// Default value. /// Value of element as the specified type or default value. public T Get(string childName, T defaultValue) { if (!hasChildNodes) return defaultValue; #if !NETFX_CORE return Get(_element[childName], defaultValue); #else return Get(GetFirstChild(_element, childName), defaultValue); #endif } public IEnumerator GetEnumerator() { for (int i = 0; i < count; i++) { yield return this[i]; } } public Vector2 GetLatLng(string subNodeName) { RealWorldTerrainXML subNode = this[subNodeName]; return new Vector2(subNode.Get("lng"), subNode.Get("lat")); } /// /// Get NamespaceManager for current xml node. /// /// Namespace prefix. /// NamespaceManager public RealWorldTerrainXMLNamespaceManager GetNamespaceManager(string prefix = null) { #if !NETFX_CORE RealWorldTerrainXMLNamespaceManager nsmgr = new RealWorldTerrainXMLNamespaceManager(document.NameTable); if (prefix == null) prefix = element.GetPrefixOfNamespace(element.NamespaceURI); nsmgr.AddNamespace(prefix, element.NamespaceURI); #else RealWorldTerrainXMLNamespaceManager nsmgr = new RealWorldTerrainXMLNamespaceManager(new System.Xml.NameTable()); if (prefix == null) prefix = element.Prefix.ToString(); nsmgr.AddNamespace(prefix, element.NamespaceUri.ToString()); #endif return nsmgr; } public bool HasChild(string childName) { if (!hasChildNodes) return false; #if !NETFX_CORE return _element[childName] != null; #else return GetFirstChild(_element, childName) != null; #endif } /// /// Converts XMLNode coordinates from Google Maps into Vector2. /// /// XMLNode coordinates from Google Maps. /// Coordinates as Vector2. public static Vector2 GetVector2FromNode(RealWorldTerrainXML node) { float lng = node.Get("lng"); float lat = node.Get("lat"); return new Vector2(lng, lat); } /// /// Loads the XML from a string. /// /// XML string. /// First element. public static RealWorldTerrainXML Load(string xmlString) { try { XmlDocument document = new XmlDocument(); document.LoadXml(xmlString); return new RealWorldTerrainXML(document.DocumentElement); } catch { Debug.Log("Can not load XML from string:\n" + xmlString); return new RealWorldTerrainXML(); } } /// /// Removes this element from the XML. /// public void Remove() { if (_element == null || _element.ParentNode == null) return; _element.ParentNode.RemoveChild(_element); } /// /// Removes child element from the XML. /// /// Name of child element. public void Remove(string childName) { if (!hasChildNodes) return; #if !NETFX_CORE _element.RemoveChild(_element[childName]); #else _element.RemoveChild(GetFirstChild(_element, childName)); #endif } /// /// Removes child element from the XML. /// /// Index of child element. public void Remove(int childIndex) { if (!hasChildNodes) return; if (childIndex < 0 || childIndex >= _element.ChildNodes.Count) return; _element.RemoveChild(_element.ChildNodes[childIndex]); } /// /// Sets the value of the element. /// /// Value of element. private void SetChild(string value) { if (_element == null || _document == null) return; _element.AppendChild(_document.CreateTextNode(value)); } /// /// Gets the value of the element as string. /// /// Value of the element as string. public string Value() { return Value(); } /// /// Gets the value of the element as the specified type. /// /// Type of element. /// Value as the specified type. public T Value() { return Get(_element); } } }