/// <summary> /// Maps a list of simple values into a collection /// </summary> /// <typeparam name="T">Type of value to return</typeparam> /// <param name="source">XPathProcessor to use</param> /// <param name="collectionNode">Collection node name (may be null)</param> /// <param name="nodeName">Node name to use</param> /// <param name="func">Function to access the data from the XPathProcessor, e.g. x => x.ToInt(CurrentXPath)</param> /// <returns>List of values</returns> public static List <T> MapList <T>(this XPathProcessor source, string collectionNode, string nodeName, Func <XPathProcessor, T> func) { if (!string.IsNullOrEmpty(collectionNode)) { source.Push(collectionNode); } var list = new List <T>(); var index = 1; while (source.HasElement(nodeName, index: index)) { source.Push(nodeName, index: index); try { list.Add(func(source)); index++; } finally { source.Pop(); } } if (!string.IsNullOrEmpty(collectionNode)) { source.Pop(); } return(list); }
/// <copydocfrom cref="IXmlMapper{T, D}.Map(T, string, string, bool)" /> public TDestination Map(XPathProcessor source, string nodeName, string xmlNamespace = "", bool outputDefault = false) { RegisterNamespace(source, NamespacePrefix, Namespace); // Push both the node and the namespace - presumption that the namespace applies to the node source.Push(nodeName, Namespace); try { if (!source.CurrentNode()) { return(null); } RegisterNamespace(source, XsiPrefix, XsiNamespace); var xmlType = source.ToString("type", XsiPrefix, isAttribute: true); TDestination destination; // This mapper can handle it if there's no type specified or it's our type if (string.IsNullOrEmpty(xmlType) || string.IsNullOrEmpty(XmlType)) { destination = CreateAndMap(source); } else { var t = XmlTypeInfo(source, xmlType); if (XmlTypeNamespace == t.Item1 && XmlType == t.Item2) { destination = CreateAndMap(source); } else { // Otherwise, pass off to the engine // NB Use the current namespace for the node name, not the target mapper's if (!nodeName.Contains(":")) { nodeName = string.Format("{0}:{1}", NamespacePrefix, nodeName); } try { destination = Engine.Map <XPathProcessor, TDestination>(source, nodeName, t.Item1, t.Item2); } catch (XmlTypeMappingException) { // try to map with our base engine destination = this.CreateAndMap(source); } } } return(destination); } finally { // Make sure we unwind the stack in all cases source.Pop(); } }
protected TDestination Map(XPathProcessor source, string nodeName, string xmlNamespace, string xmlPrefix, int index) { RegisterNamespace(source, NamespacePrefix, Namespace); // Namespace and node provide context, however the prefix if present overrides the node's actual namespace source.Push(nodeName, Namespace, xmlPrefix, index); try { if (!source.CurrentNode()) { return(null); } var xmlType = string.Empty; RegisterNamespace(source, XsiPrefix, XsiNamespace); xmlType = source.ToString("type", XsiPrefix, isAttribute: true); TDestination destination; // This mapper can handle it if there's no type specified or it's our type or if it is the base mapper for an unknown type if (string.IsNullOrEmpty(xmlType) || string.IsNullOrEmpty(XmlType)) { destination = CreateAndMap(source); } else { var t = XmlTypeInfo(source, xmlType); if (t.Item1 == XmlTypeNamespace && t.Item2 == XmlType) { // We're responsible destination = CreateAndMap(source); } else { // Need a mapper for this xsi:type try { destination = XsiMapper(source, nodeName, t.Item1, t.Item2, index); } catch (XmlTypeMappingException) { // if we don't get one try with this base one destination = this.CreateAndMap(source); } } } return(destination); } finally { // Make sure we unwind the stack in all cases source.Pop(); } }
public virtual List <TDestination> MapList(XPathProcessor source, string collectionNode, string nodeName, string collectionNodeNamespacePrefix = "", string collectionItemNodeNamespacePrefix = "", bool outputDefault = false) { // Default namespace this.RegisterNamespace(source, this.NamespacePrefix, this.Namespace); string collNamespace; var list = new List <TDestination>(); if (string.IsNullOrWhiteSpace(collectionNodeNamespacePrefix)) { // It's the same as normal collectionNodeNamespacePrefix = this.NamespacePrefix; collNamespace = this.Namespace; } else { // Look it up. collNamespace = source.LookupNamespace(collectionNodeNamespacePrefix); if (string.IsNullOrWhiteSpace(collNamespace)) { throw new MappingException(string.Format("No namespace registered for {0}", collectionNodeNamespacePrefix)); } } if (!string.IsNullOrEmpty(collectionNode)) { source.Push(collectionNode, collNamespace, collectionNodeNamespacePrefix); } if (string.IsNullOrEmpty(nodeName)) { nodeName = this.NodeName; } var index = 1; TDestination item; do { item = this.Map(source, nodeName, string.Empty, collectionItemNodeNamespacePrefix, index++); if (item != null) { list.Add(item); } }while (item != null); if (!string.IsNullOrEmpty(collectionNode)) { source.Pop(); } return(list); }
/// <summary> /// Map an entity for a particular xsi:type. /// </summary> /// <param name="source">Processor to use</param> /// <param name="nodeName">Node name to use.</param> /// <param name="xmlNamespace">XML namespace to use.</param> /// <param name="xmlType">XML type to use</param> /// <param name="index">Index to use.</param> /// <returns>A new instance of the TDestination class mapped from the source.</returns> private TDestination XsiMapper(XPathProcessor source, string nodeName, string xmlNamespace, string xmlType, int index) { // Unwind the current node position, we're about to do the same again. source.Pop(); try { // NB Use the current namespace for the node name, not the target mapper's var destination = this.Engine.Map <XPathProcessor, TDestination>( source, nodeName, xmlNamespace, xmlType, this.NamespacePrefix, index); return(destination); } finally { // Put it back where it was source.Push(nodeName, xmlNamespace, this.NamespacePrefix, index); } }