1

dom4j (非常に優れた Java XML ライブラリ) には、非常に便利な呼び出しがあります。それらの XPathNavigator オブジェクトに相当するもので、その特定のノードを提供する一意の Xpath ステートメントを要求できます。.NET XML ライブラリを使用してこれを取得するにはどうすればよいですか?

4

1 に答える 1

0

私はこれをやり遂げました。

注: これには、XPathNavigator オブジェクトの基になる XmlDocument が必要です。XmlDocument をラップしていない XPathNavigator オブジェクトを持つことができますが、そのような場合、これは機能しません。

これを呼び出すには、XPathNavigator オブジェクトが現在存在する XmlNode を渡します。それは XPathNavigator.UnderlyingObject に含まれています。

また、名前空間を明示的に設定する場合は、キーが名前空間 uri で値がプレフィックスである Dictionary に渡す必要があります。基になる XmlDocument は、元の XML で定義されている名前空間を使用します。読み込み後に割り当てられた名前空間ではありません (理由はわかりません)。名前空間を明示的に設定していない場合は、null を渡すことができます。

完全なコードは、XML Get Unique XPathの zip にあります。

using System.Collections.Generic; 
using System.Text; 
using System.Xml; 

/// <summary> 

/// For an XmlNode in an XmlDocument, can determine the XPath 
///to return that specific node. Can also then determine the non-specific 

/// XPath to a subsequent child node (the XPath that will return that node AND ALSO any peer nodes of the same name(s)). 

/// </summary> 

public class NodeLocator 

{ 

    private NodeLocator next; 

    private readonly XmlNode node; 

    private readonly Dictionary<string, string> namespaceMap; 



    private NodeLocator(Dictionary<string, string> namespaceMap, XmlNode node) 

    { 

        this.node = node; 

        this.namespaceMap = namespaceMap ?? new Dictionary<string, string>(); 

    } 



    /// <summary> 

    /// Get the unique XPath for the passed in node. 

    /// </summary> 

    /// <param name="namespaceMap">If namespace prefixes are different from the raw XmlDocument, this dictionaru is key=uri, value=prefix.</param> 

    /// <param name="node">The node to get the unique XPath to.</param> 

    /// <returns>The unique XPath to node.</returns> 

    public static string GetUniqueLocation(Dictionary<string, string> namespaceMap, XmlNode node) 

    { 

        NodeLocator loc = new NodeLocator(namespaceMap, node); 

        while (node.ParentNode != null) 

        { 

            node = node.ParentNode; 

            if (node is XmlDocument) 

                break; 

            NodeLocator parentloc = new NodeLocator(namespaceMap, node); 

            parentloc.next = loc; 

            loc = parentloc; 

        } 

        return loc.Xpath(true); 

    } 



    /// <summary> 

    /// Get the unique XPath for the passed in node. It uses the unique XPath from the root to the parent and then non-unique XPath from the parent to the node. 

    /// </summary> 

    /// <param name="namespaceMap">If namespace prefixes are different from the raw XmlDocument, this dictionaru is key=uri, value=prefix.</param> 

    /// <param name="parent">The node to get the unique XPath to.</param> 

    /// <param name="node">The node to get the NON-unique XPath to.</param> 

    /// <returns>The unique XPath to node.</returns> 

    public static string GetLocation(Dictionary<string, string> namespaceMap, XmlNode parent, XmlNode node) 

    { 

        NodeLocator loc = new NodeLocator(namespaceMap, node); 

        while ((node.ParentNode != null) && (node.ParentNode != parent)) 

        { 

            node = node.ParentNode; 

            if (node is XmlDocument) 

                break; 

            NodeLocator parentloc = new NodeLocator(namespaceMap, node); 

            parentloc.next = loc; 

            loc = parentloc; 

        } 

        return loc.Xpath(false); 

    } 



    private string Xpath(bool unique) 

    { 

        StringBuilder sb = new StringBuilder(); 

        NodeLocator loc = this; 

        do 

        { 

            if (loc.node.Name.StartsWith("#")) 

            { 

                if (loc.node.Name == "#document") 

                    sb.Append('/'); 

            } 

            else 

            { 

                sb.Append('/'); 

                if (loc.node is XmlAttribute) 

                    sb.Append('@'); 

                sb.Append(FullName(loc.node)); 

                if (unique) 

                { 

                    sb.Append('['); 

                    sb.Append(loc.IndexInParent); 

                    sb.Append(']'); 

                } 

            } 

            loc = loc.next; 

        } while (loc != null); 



        // no leading / for non-unique 

        if ((!unique) && (sb.Length > 0)) 

            sb.Remove(0, 1); 

        return sb.ToString(); 

    } 



    private string FullName(XmlNode _node) 

    { 

        if (string.IsNullOrEmpty(_node.NamespaceURI) || (!namespaceMap.ContainsKey(_node.NamespaceURI))) 

            return _node.Name; 

        return namespaceMap[_node.NamespaceURI] + ':' + _node.LocalName; 

    } 



    private int IndexInParent 

    { 

        get 

        { 

            int indexInParent = 1; 

            XmlNode parent = node.ParentNode; 

            string nodeName = FullName(node); 

            if (parent != null) 

            { 

                foreach (XmlNode child in parent.ChildNodes) 

                { 

                    if (child == node) 

                        break; 

                    if (FullName(child) == nodeName) 

                    { 

                        indexInParent++; 

                    } 

                } 

            } 

            return indexInParent; 

        } 

    } 

}
于 2010-12-03T23:34:35.130 に答える