XPathResult
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
namespace Castle.Components.DictionaryAdapter
{
public class XPathResult
{
public readonly bool CanWrite;
private readonly object matchingBehavior;
private readonly Func<XPathNavigator> create;
private static readonly Dictionary<Type, string> XmlDataTypes = new Dictionary<Type, string> {
{
typeof(int),
"int"
},
{
typeof(long),
"long"
},
{
typeof(short),
"short"
},
{
typeof(float),
"float"
},
{
typeof(double),
"double"
},
{
typeof(bool),
"boolean"
},
{
typeof(DateTime),
"dateTime"
},
{
typeof(byte),
"byte"
},
{
typeof(uint),
"uint"
},
{
typeof(ulong),
"ulong"
},
{
typeof(ushort),
"ushort"
}
};
public bool IsContainer {
get {
if (matchingBehavior != null)
return matchingBehavior is XmlArrayAttribute;
return true;
}
}
public Type Type { get; set; }
public PropertyDescriptor Property { get; set; }
public string Key { get; set; }
public object Result { get; set; }
public XPathContext Context { get; set; }
public XPathNavigator Container { get; set; }
public XmlMetadata XmlMeta { get; set; }
public bool OmitPolymorphism { get; set; }
public bool IsNullable {
get {
if (Result is XPathNavigator && ((XPathNavigator)Result).NodeType != XPathNodeType.Element)
return false;
if (matchingBehavior == null)
return Context.IsNullable;
if (matchingBehavior is XmlElementAttribute)
return ((XmlElementAttribute)matchingBehavior).IsNullable;
if (matchingBehavior is XmlArrayAttribute)
return ((XmlArrayAttribute)matchingBehavior).IsNullable;
if (matchingBehavior is XmlArrayItemAttribute)
return ((XmlArrayItemAttribute)matchingBehavior).IsNullable;
return Context.IsNullable;
}
}
public XPathResult(PropertyDescriptor property, string key, object result, XPathContext context, object matchingBehavior)
: this(property, key, result, context, matchingBehavior, null)
{
}
public XPathResult(Type type, object result, XPathContext context, object matchingBehavior)
: this(null, null, result, context, matchingBehavior, null)
{
Type = type;
}
public XPathResult(PropertyDescriptor property, string key, object result, XPathContext context, object matchingBehavior, Func<XPathNavigator> create)
{
Result = result;
Property = property;
Key = key;
Type = ((property != null) ? Property.PropertyType : null);
Context = context;
this.create = create;
this.matchingBehavior = matchingBehavior;
CanWrite = (create != null || result is XPathNavigator);
}
public XPathNavigator (bool demand)
{
GetNavigator(demand, false, out XPathNavigator result);
return result;
}
public bool (bool demand, bool nillable, out XPathNavigator result)
{
if (Result is XPathNavigator) {
result = (XPathNavigator)Result;
if (!nillable)
return true;
return GetNillable(ref result);
}
if (Result is XPathNodeIterator) {
result = ((XPathNodeIterator)Result).Cast<XPathNavigator>().FirstOrDefault();
if (!nillable)
return true;
return GetNillable(ref result);
}
if (demand && create != null) {
result = create();
Result = result;
return true;
}
result = null;
return true;
}
public XPathResult GetNodeAt(Type type, int index)
{
XPathNavigator xPathNavigator = Container;
if (IsContainer) {
if (xPathNavigator != null)
xPathNavigator = Container.SelectSingleNode($"""{index + 1}""");
} else if (Result is XPathNodeIterator) {
XPathNavigator[] array = ((XPathNodeIterator)Result).Cast<XPathNavigator>().ToArray();
xPathNavigator = array[index];
}
return new XPathResult(type, xPathNavigator, Context, Context.ListItemMeta ?? matchingBehavior);
}
public IEnumerable<XPathResult> GetNodes(Type type, Func<Type, XmlMetadata> getXmlMeta)
{
Container = null;
XPathNodeIterator xPathNodeIterator = Result as XPathNodeIterator;
IEnumerable<XPathNavigator> source = Enumerable.Empty<XPathNavigator>();
if (xPathNodeIterator == null) {
Container = (Result as XPathNavigator);
if (IsContainer && Container != null) {
if (Context.IsNil(Container))
return null;
if (Context.ListItemMeta != null)
return Context.ListItemMeta.SelectMany(delegate(XmlArrayItemAttribute item) {
string name2;
string namespaceUri2;
XmlMetadata xmlMeta2 = GetItemQualifedName(type, item, getXmlMeta, out name2, out namespaceUri2);
return from XPathNavigator r in Container.SelectChildren(name2, namespaceUri2)
select new XPathResult(item.Type ?? type, r, Context, item) {
XmlMeta = xmlMeta2
};
}).OrderBy((XPathResult r) => (XPathNavigator)r.Result, XPathPositionComparer.Instance);
source = Container.SelectChildren(XPathNodeType.Element).Cast<XPathNavigator>();
}
} else if (!IsContainer) {
source = xPathNodeIterator.Cast<XPathNavigator>();
} else {
List<XPathNavigator> parents = xPathNodeIterator.Cast<XPathNavigator>().ToList();
Container = parents.FirstOrDefault();
if (Context.IsNil(Container))
return null;
if (Context.ListItemMeta != null)
return Context.ListItemMeta.SelectMany(delegate(XmlArrayItemAttribute item) {
string name;
string namespaceUri;
XmlMetadata xmlMeta = GetItemQualifedName(type, item, getXmlMeta, out name, out namespaceUri);
return from r in parents.SelectMany((XPathNavigator p) => p.SelectChildren(name, namespaceUri).Cast<XPathNavigator>())
select new XPathResult(item.Type ?? type, r, Context, item) {
XmlMeta = xmlMeta
};
}).OrderBy((XPathResult r) => (XPathNavigator)r.Result, XPathPositionComparer.Instance);
source = parents.SelectMany((XPathNavigator p) => p.SelectChildren(XPathNodeType.Element).Cast<XPathNavigator>());
}
return from r in source
select new XPathResult(type, r, Context, matchingBehavior);
}
public bool ReadObject(out object value)
{
if (GetNavigator(false, true, out XPathNavigator result) && result != null) {
foreach (IXPathSerializer serializer in Context.Serializers) {
if (serializer.ReadObject(this, result, out value))
return true;
}
}
value = null;
return false;
}
public bool WriteObject(object value)
{
XPathNavigator navigator = GetNavigator(true);
foreach (IXPathSerializer serializer in Context.Serializers) {
if (serializer.WriteObject(this, navigator, value))
return true;
}
return false;
}
private XmlMetadata GetItemQualifedName(Type type, XmlArrayItemAttribute item, Func<Type, XmlMetadata> getXmlMeta, out string name, out string namespaceUri)
{
name = item.ElementName;
namespaceUri = item.Namespace;
type = (item.Type ?? type);
XmlMetadata xmlMetadata = getXmlMeta(type);
if (string.IsNullOrEmpty(name)) {
if (xmlMetadata != null)
name = xmlMetadata.XmlType.TypeName;
else
name = GetDataType(type);
namespaceUri = null;
}
namespaceUri = Context.GetEffectiveNamespace(namespaceUri);
return xmlMetadata;
}
public XPathResult CreateNode(Type type, object value, Func<Type, XmlMetadata> getXmlMeta)
{
string name = null;
string namespaceUri = null;
string text = null;
bool omitPolymorphism = false;
XmlMetadata xmlMetadata = getXmlMeta(type);
object obj = matchingBehavior;
if (xmlMetadata != null) {
name = xmlMetadata.XmlType.TypeName;
text = xmlMetadata.XmlType.Namespace;
}
if (value != null)
type = ((!(value is IDictionaryAdapter)) ? value.GetType() : ((IDictionaryAdapter)value).Meta.Type);
if (xmlMetadata == null)
name = GetDataType(type);
if (Context.ListItemMeta != null) {
XmlArrayItemAttribute xmlArrayItemAttribute = Context.ListItemMeta.FirstOrDefault((XmlArrayItemAttribute li) => (li.Type ?? type) == type);
if (xmlArrayItemAttribute != null) {
obj = xmlArrayItemAttribute;
if (xmlArrayItemAttribute.Type != (Type)null) {
type = xmlArrayItemAttribute.Type;
xmlMetadata = getXmlMeta(xmlArrayItemAttribute.Type);
} else
type = type;
if (string.IsNullOrEmpty(xmlArrayItemAttribute.ElementName)) {
if (xmlMetadata != null) {
name = xmlMetadata.XmlType.TypeName;
text = xmlMetadata.XmlType.Namespace;
} else
name = GetDataType(type);
} else {
name = xmlArrayItemAttribute.ElementName;
namespaceUri = xmlArrayItemAttribute.Namespace;
}
omitPolymorphism = true;
}
}
XPathNavigator xPathNavigator = null;
if (IsContainer) {
if (Container == null && create != null)
Container = create();
if (Container != null)
xPathNavigator = Context.AppendElement(name, namespaceUri, Container);
} else if (create != null) {
xPathNavigator = create();
}
if (!string.IsNullOrEmpty(text))
Context.CreateNamespace(null, text, xPathNavigator);
XPathResult xPathResult = new XPathResult(type, xPathNavigator, Context, obj);
xPathResult.XmlMeta = xmlMetadata;
xPathResult.OmitPolymorphism = omitPolymorphism;
return xPathResult;
}
public bool RemoveAt(int index)
{
return GetNodeAt(null, index).Remove(true);
}
public bool Remove(bool nillable)
{
if (Result is XPathNavigator) {
XPathNavigator xPathNavigator = (XPathNavigator)Result;
if (nillable && IsNullable) {
RemoveChildren(xPathNavigator);
Context.MakeNil(xPathNavigator);
return false;
}
xPathNavigator.DeleteSelf();
return true;
}
if (Result is XPathNodeIterator) {
bool flag = false;
XPathNavigator[] array = ((XPathNodeIterator)Result).Cast<XPathNavigator>().ToArray();
for (int i = 0; i < array.Length; i++) {
if (i == 0 && nillable && IsNullable) {
RemoveChildren(array[0]);
Context.MakeNil(array[0]);
flag = true;
} else
array[i].DeleteSelf();
}
if (flag)
return false;
}
Result = null;
if (nillable && IsNullable) {
XPathNavigator navigator = GetNavigator(true);
if (navigator != null) {
Context.MakeNil(navigator);
Result = navigator;
return false;
}
}
return true;
}
public XPathNavigator RemoveChildren()
{
XPathNavigator navigator = GetNavigator(true);
RemoveChildren(navigator);
return navigator;
}
private static void (XPathNavigator node)
{
if (node != null) {
IEnumerable<XPathNavigator> source = from XPathNavigator child in node.SelectChildren(XPathNodeType.All)
where child.NodeType != XPathNodeType.Namespace
select child;
XPathNavigator[] array = source.ToArray();
foreach (XPathNavigator xPathNavigator in array) {
xPathNavigator.DeleteSelf();
}
}
}
private bool (ref XPathNavigator source)
{
if (source != null && IsNullable && Context.IsNil(source)) {
source = null;
return false;
}
return true;
}
private static string GetDataType(Type type)
{
if (XmlDataTypes.TryGetValue(type, out string value))
return value;
value = type.Name.ToLower();
return value;
}
}
}