/* 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);
}
}
}