/// <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();
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        /// <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);
            }
        }