コード例 #1
0
        private static object GetReturnTypeDefault(XPathEvaluationReturnType expectedReturnType)
        {
            // According to https://docs.microsoft.com/en-us/dotnet/api/system.xml.xpath.xpathnavigator.evaluate?view=netframework-4.5
            //  XPathNavigator.Evaluate can only return one of the following data types:
            //  bool, double, string or XPathNodeIterator.  These correspond to the values of the
            //  XPathEvaluationReturnType enum, where XPathNodeIterator can represent a Nodeset or
            //  a Node.

            IDictionary <XPathEvaluationReturnType, Type> returnTypeMappings = ReturnTypeMappings;

            string errorMessage = null;

            Type expectedType = returnTypeMappings.GetValueOrNull(expectedReturnType);

            if (expectedType == null)
            {
                errorMessage = string.Format("Invalid return type.  "
                                             + "Result of XPath evaluation cannot return type {0}.",
                                             expectedReturnType);
                throw new ArgumentException(errorMessage);
            }

            if (expectedType.IsValueType)
            {
                return(Activator.CreateInstance(expectedType));
            }

            // Can return null for all reference types.
            return(null);
        }
コード例 #2
0
 /// <summary>
 /// Applies the XPath expression to the XML content and returns the result.
 /// </summary>
 /// <param name="xpathExpression">The XPath expression to apply.</param>
 /// <param name="content">The XML content the Xpath expression will be applied to.</param>
 /// <param name="returnType">The return type: Boolean, Number, String, Node or Nodeset.</param>
 /// <returns>The result of applying the XPath expression to the XML content.  The type
 /// returned will depend on the specified return type:  Boolean will return a
 /// System.Boolean, Number will return a System.Double, String will return a
 /// System.String, and Node or Nodeset will return an XPathNavigator object representing
 /// a single node.  Return types Node and Nodeset are equivalent: They will each only
 /// return a single node.  If the XPath expression matches multiple nodes then only the
 /// first node or its value will be returned, depending on the return type specified.</returns>
 /// <remarks>This method is only used to read the contents of a node, as either a string
 /// or a boolean, or to check the existence of a node.  When multiple  nodes match the
 /// XPath expression only the contents of the first is ever read, and only the first node
 /// is needed to prove existence.  Hence the return type Nodeset is identical to return
 /// type Node, returning only a single node.
 ///
 /// The original Java implementation had a charset parameter for this method.
 /// However, in .NET charset or encoding does not need to be specified as the content
 /// being parsed is a .NET string, which does not have encoding associated with it.  It
 /// would be different if we had to parse the contents of a stream or a file.</remarks>
 public static object extractXPath(string xpathExpression, string content,
                                   XPathEvaluationReturnType returnType)
 {
     // Use the java Xpath API to return a NodeList to the caller so they can
     // iterate through
     return(extractXPath(new Dictionary <string, string>(), xpathExpression, content,
                         returnType));
 }
コード例 #3
0
        private void ExtractNonExistentNode(string xpathExpression,
                                            XPathEvaluationReturnType returnType)
        {
            // Arrange.
            string xml = "<a><b>test</b><c>1</c><c>2</c></a>";

            // Act.
            object rawValue =
                XmlTools.extractXPath(xpathExpression, xml, returnType);

            // Assert.
            Assert.IsNull(rawValue);
        }
コード例 #4
0
        private static object GetNodeValue(object rawResult, XPathEvaluationReturnType returnType)
        {
            if (rawResult == null)
            {
                return(null);
            }

            XPathNodeIterator iterator = rawResult as XPathNodeIterator;

            if (iterator == null)
            {
                return(rawResult);
            }

            // If there is a match the Count will be a positive integer, if there is no match
            //  the Count will be 0.  Can't depend on the node the iterator moves to as if
            //  there is no match it will just move to the root node.  So we have to check the
            //  Count to determine if there is a match or not.
            if (iterator.Count == 0)
            {
                return(null);
            }

            iterator.MoveNext();
            XPathNavigator node = iterator.Current;

            if (node == null)
            {
                return(rawResult);
            }

            switch (returnType)
            {
            case XPathEvaluationReturnType.Boolean:
                return(node.ValueAsBoolean);

            case XPathEvaluationReturnType.Number:
                return(node.ValueAsDouble);

            case XPathEvaluationReturnType.String:
                return(node.Value);

            case XPathEvaluationReturnType.Node:
            case XPathEvaluationReturnType.Nodeset:
                return(node);
            }
            return(rawResult);
        }
コード例 #5
0
        private void ExtractValueFromXml <T>(string xpathExpression,
                                             XPathEvaluationReturnType returnType, T expectedValue)
        {
            // Arrange.
            string xml = "<a><b>test</b><c>1</c><c>2</c></a>";

            // Act.
            object rawValue =
                XmlTools.extractXPath(xpathExpression, xml, returnType);
            object actualValue = default(T);

            if (typeof(T) == typeof(string))
            {
                actualValue = rawValue.ToString();
            }
            else
            {
                actualValue = (T)rawValue;
            }

            // Assert.
            Assert.AreEqual(expectedValue, actualValue);
        }
コード例 #6
0
        private static void CheckExtractionReturnType(object returnValue,
                                                      XPathEvaluationReturnType expectedReturnType)
        {
            // According to https://docs.microsoft.com/en-us/dotnet/api/system.xml.xpath.xpathnavigator.evaluate?view=netframework-4.5
            //  XPathNavigator.Evaluate can only return one of the following data types:
            //  bool, double, string or XPathNodeIterator.  These correspond to the values of the
            //  XPathEvaluationReturnType enum, where XPathNodeIterator can represent a Nodeset or
            //  a Node.

            IDictionary <XPathEvaluationReturnType, Type> returnTypeMappings = ReturnTypeMappings;

            string errorMessage = null;

            Type expectedType = returnTypeMappings.GetValueOrNull(expectedReturnType);

            if (expectedType == null)
            {
                errorMessage = string.Format("Invalid return type.  "
                                             + "Result of XPath evaluation cannot return type {0}.",
                                             expectedReturnType);
                throw new ArgumentException(errorMessage);
            }

            Type actualType = returnValue.GetType();

            // Actual type could be derived from the expected type, for example the actual type
            //  could be XPathSelectionIterator which is derived from the expected type
            //  XPathNodeIterator.  So use IsAssignableFrom instead of equality comparison.
            // Assume any return type could be converted to a string.
            if (!expectedType.IsAssignableFrom(actualType) && expectedType != typeof(string))
            {
                errorMessage = string.Format("XPath expression return type {0} is not compatible "
                                             + "with the specified return type {1}.",
                                             actualType.FullName, expectedReturnType);
                throw new XPathException(errorMessage);
            }
        }
コード例 #7
0
 private void ExtractNonExistentTextNode(XPathEvaluationReturnType returnType)
 {
     ExtractNonExistentNode("/a/nonExistentNode/text()", returnType);
 }
コード例 #8
0
        /// <summary>
        /// Applies the XPath expression to the XML content and returns the result.
        /// </summary>
        /// <param name="ns">The namespaces map, which lists the namespaces in the XML and their
        /// aliases.</param>
        /// <param name="xpathExpression">The XPath expression to apply.</param>
        /// <param name="content">The XML content the Xpath expression will be applied to.</param>
        /// <param name="returnType">The return type: Boolean, Number, String, Node or Nodeset.</param>
        /// <returns>The result of applying the XPath expression to the XML content.  The type
        /// returned will depend on the specified return type:  Boolean will return a
        /// System.Boolean, Number will return a System.Double, String will return a
        /// System.String, and Node or Nodeset will return an XPathNavigator object representing
        /// a single node.  Return types Node and Nodeset are equivalent: They will each only
        /// return a single node.  If the XPath expression matches multiple nodes then only the
        /// first node or its value will be returned, depending on the return type specified.</returns>
        /// <remarks>This method is only used to read the contents of a node, as either a string
        /// or a boolean, or to check the existence of a node.  When multiple  nodes match the
        /// XPath expression only the contents of the first is ever read, and only the first node
        /// is needed to prove existence.  Hence the return type Nodeset is identical to return
        /// type Node, returning only a single node.
        ///
        /// The original Java implementation had a charset parameter for this method.
        /// However, in .NET charset or encoding does not need to be specified as the content
        /// being parsed is a .NET string, which does not have encoding associated with it.  It
        /// would be different if we had to parse the contents of a stream or a file.</remarks>
        public static object extractXPath(IDictionary <string, string> ns, string xpathExpression,
                                          string content, XPathEvaluationReturnType returnType)
        {
            if (string.IsNullOrWhiteSpace(xpathExpression))
            {
                throw new ArgumentException("XPath expression is null");
            }
            if (string.IsNullOrWhiteSpace(content))
            {
                throw new ArgumentException("XML is null");
            }

            XPathDocument       document         = null;
            XmlNamespaceManager namespaceManager = null;

            using (StringReader sr = new StringReader(content))
                using (XmlReader xr = XmlReader.Create(sr))
                {
                    try
                    {
                        document = new XPathDocument(xr);
                    }
                    catch (Exception ex)
                    {
                        throw new ArgumentException("XML is ill-formed", ex);
                    }

                    // Handling namespaces:
                    //  XPathNavigator.Evaluate(xpath) and XPathNavigator.SelectSingleNode(xpath) both
                    //  compile the xpath expression into an XPathExpression object, using
                    //  XPathExpression.Compile(string xpath, IXmlNamespaceResolver nsResolver).  They
                    //  pass null in as the IXmlNamespaceResolver.  This is equivalent to calling
                    //  XPathNavigator.Evaluate(string xpath, IXmlNamespaceResolver resolver) or
                    //  XPathNavigator.SelectSingleNode(string xpath, IXmlNamespaceResolver resolver),
                    //  respectively, with the resolver set to null.  So we'll just pass null in as
                    //  the resolver if we have no namespaces.
                    namespaceManager = GetNamespaceManager(ns, xr.NameTable);
                }

            object         result    = null;
            XPathNavigator navigator = document.CreateNavigator();

            try
            {
                result = navigator.Evaluate(xpathExpression, namespaceManager);
                result = GetNodeValue(result, returnType);
                if (result == null)
                {
                    return(null);
                }
                return(result);
            }
            catch (ArgumentException ex)
            {
                throw new ArgumentException(
                          "xPath expression would return a node set: " + xpathExpression,
                          ex);
            }
            catch (XPathException)
            {
                throw new ArgumentException(
                          "xPath expression is not valid: " + xpathExpression);
            }
            catch (Exception ex)
            {
                throw new ArgumentException(
                          "Error parsing XML with xPath expression " + xpathExpression, ex);
            }
        }