Freigeben über


Der XPathNavigator über verschiedene Speicher

Der XPathNavigator vereinfacht die Ausführung von XPath-Abfragen über einen beliebigen Speicher, der die IXPathNavigable-Schnittstelle implementiert. Die Klassen, die die IXPathNavigable-Schnittstelle implementieren, sind XPathDocument, XmlDocument und XmlDataDocument.

Die XPathDocument-Klasse ermöglicht XPath-Abfragen über XML-Datenströme. Sie ist für die Durchführung von XPath-Abfragen und XSLT-Transformationen optimiert. Dies ist die bevorzugte Klasse für XSLT-Transformationen, wenn die XPath-Leistung die oberste Priorität hat.

Die XmlDocument-Klasse stellt nicht nur eine bearbeitbare Dokumentobjektmodell (DOM)-Ansicht des XML-Codes bereit, sondern ermöglicht auch XPath über Daten. Das XPathDocument und das XmlDocument weisen in Bezug auf die Ergebnisse von Abfragen über die gleichen XML-Daten das gleiche Verhalten auf. Das XmlDocument ist für XPath-Abfragen aufgrund der Bearbeitungsfunktionen in dieser Klasse weniger leistungsstark als das XPathDocument.

Die XmlDataDocument-Klasse bietet ein voll kompatibles Dokumentobjektmodell, das mit einem DataSet synchronisiert wird. Es erbt von der XmlDocument-Klasse und wird verwendet, um eine hierarchische XML-Ansicht der relationalen Daten zu erhalten. Es kann zum Ausführen von XPath-Abfragen für die XML-Darstellung der in einem Dataset gespeicherten Daten verwendet werden. Weitere Informationen über das XmlDataDocument finden Sie unter Synchronisieren eines DataSets mit einem XmlDataDocument.

Um XPath-Abfragen für eine dieser Klassen auszuführen, rufen Sie die CreateNavigator-Funktion auf, damit ein XPathNavigator zurückgegeben wird. Mit dem XPathNavigator können Sie dann XPath-Abfragen über das Dokument ausführen, wie in den weiteren Abschnitten beschrieben.

Sie haben auch die Möglichkeit, die XPathNavigator-Klasse zu erweitern, um eigene Navigatoren zu definieren. Dazu müssen Sie eine virtuelle Knotenstruktur erstellen und Methoden zum Navigieren in dieser Struktur implementieren. Sobald diese Knotenstruktur geschrieben ist, ist die Durchführung von XPath-Abfragen aktiviert. Die Select-Methoden in der XPathNavigator-Klasse werden implementiert und benötigen nur diese Struktur, um zu funktionieren. Im folgenden Beispiel wird ein XPathNavigator über ein Dateisystem implementiert.

Beginnen Sie, indem Sie die virtuelle Knotenstruktur erstellen. Diese ist eine Struktur, die das zugrunde liegende Dateisystem so offen legt, dass es alle Informationen im XML-Infoset enthält. Diese XML-Struktur wird offen gelegt, indem die Methoden in der XPathNavigator-Klasse, die Informationen über Knoten zurückgeben, überschrieben werden. In diesem Beispiel werden Verzeichnisse und Dateien als Elemente offen gelegt. Die Struktur des Dateisystems wird in der Struktur des offen gelegten XML-Infosets gespiegelt. Elemente, die Verzeichnisse darstellen, haben den lokalen Namen und den Zeitpunkt der Erstellung des Verzeichnisses als Attribute. Elemente, die Dateien darstellen, haben den lokalen Namen, den Zeitpunkt der Erstellung und die Länge der Datei als Attribute. Sie können für dieses Dateisystem Abfragen wie /abc/xml ausführen. Diese wählt alle Verzeichnisse oder Dateien mit dem lokalen Namen xml aus, die sich in Verzeichnissen mit dem lokalen Namen abc befinden.

Um diese Struktur offen zu legen, müssen die folgenden Knoteneigenschaften überschrieben werden.

  • NodeType
  • LocalName
  • Name
  • Prefix
  • Value
  • BaseURI
  • IsEmptyElement
  • XmlLang
  • NameTable

Um diese Struktur verfügbar zu machen, müssen die folgenden Attributaccessoren überschrieben werden.

  • HasAttributes
  • GetAttributes
  • MoveToAttributes
  • MoveToFirstAttributes
  • MoveToNextAttributes

Um diese Struktur verfügbar zu machen, müssen die folgenden Namespaceaccessoren überschrieben werden.

  • GetNamespace
  • MoveToNamespace
  • MoveToFirstNamespace
  • MoveToNextNamespace

Mit diesen Methoden und Eigenschaften können Sie die zugrunde liegende Struktur vollständig als XML-Infoset offen legen.

Darüber hinaus müssen alle LocalName-, NameSpaceUri- und Prefix-Zeichenfolgen einer NameTable hinzugefügt werden, die durch die NameTable-Eigenschaft festgelegt wird. Wenn die LocalName-, die NamespaceURI- und die Prefix-Eigenschaft zurückgegeben werden, sollte die zurückgegebene Zeichenfolge aus der NameTable stammen. Namensvergleiche werden anhand eines Objektvergleichs durchgeführt, und nicht durch einen Zeichenfolgenvergleich, der deutlich langsamer ist.

Darüber hinaus müssen Methoden zum Navigieren in dieser virtuellen Knotenstruktur implementiert werden. Hierzu gehören:

  • MoveToNext
  • MoveToPrevious
  • MoveToFirst
  • MoveToFirstChild
  • MoveToParent
  • MoveToRoot
  • MoveTo
  • MoveToId
  • IsSamePosition
  • HasChildren

Diese Methoden legen die zugrunde liegende Struktur als Baumstruktur offen. Nachdem diese Methoden und Eigenschaften implementiert worden sind, laufen alle XPath-Abfragen über diesen virtuellen Knotensatz. Folgender Code erstellt z. B. einen benutzerdefinierten XPathNavigator zum Navigieren im Verzeichnis auf einer Festplatte. Ausgehend vom Verzeichnis C:\Program Files navigiert das Programm rekursiv durch die Dateien und Ordner. Auf manchen Computern kann die an die Konsole gesendete Ausgabe einen beträchtlichen Umfang annehmen. Sie können den Code ändern, so dass ein beliebiger anderer Ordner auf der Festplatte als Ausgangspunkt für das Programm verwendet wird.

using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;

public class Sample {
    static FileSystemNavigator fsn;
    public static void Main() {
        // This is the hard code for C:\ProgramFiles. You can modify this 
        // to point to a folder on your own machine for test purposes.
        fsn = new FileSystemNavigator(@"C:\Program Files");

        if (fsn.MoveToFirstChild()) {
            ShowNavigator(String.Empty);
        }
    }
    public static void ShowNavigator(string indent) {
        do {
            Console.WriteLine("{0}Name: {1}", indent, fsn.Name);
            if (fsn.HasChildren) {
                fsn.MoveToFirstChild();
                ShowNavigator(indent + "  ");
                fsn.MoveToParent();
            }
        } while (fsn.MoveToNext());
    }
}

public class FileSystemNavigator: XPathNavigator 
    {
      static int[]      NumberOfAttributes = { 2, 3 };
      //The NodeTypes used.
      public enum NodeTypes { Root, Element,  Attribute, Text };

      internal NavigatorState state;
      //Attribute names: For example a type 1 element will have a type 2 attribute named "Length"
      static String[][] AttributeIds       = new String[2][] 
               {
                  new String[] {"Name", "CreationTime"},   
                  new String[] {"Name", "CreationTime", "Length"}  
                };
      NameTable nametable;
      public FileSystemNavigator( String rootNode ) 
      {
          FileSystemInfo document = Directory.CreateDirectory(rootNode);
          nametable = new NameTable();
          nametable.Add(String.Empty);
          //if the Directory does not exist then rootNode must be a file.
          if( !document.Exists )
          {
            //create the file if it does not already exists
            FileStream tempStream = File.Open(rootNode,System.IO.FileMode.OpenOrCreate);
            tempStream.Close();
            document = new FileInfo(rootNode);
       }

         if( document.Exists )
         {
            state = new NavigatorState(document);

         }
         else
         {
            throw (new Exception("Root node must be a directory or a file"));
         }
      }
   
      public FileSystemNavigator( FileSystemInfo document ) 
      {
         nametable = new NameTable();
         nametable.Add(String.Empty);
         if( document.Exists )
         {
                state = new NavigatorState(document);
         
         }
         else
         {
             throw (new Exception("Root node must be a directory or a file"));
         }
         }

    public FileSystemNavigator( FileSystemNavigator navigator ) 
         {
         state = new NavigatorState(navigator.state);
         nametable = (NameTable)navigator.NameTable;
     
     }

       public override XPathNavigator Clone() 
       {
       return new FileSystemNavigator(this);
    }

       //NodeProperties
       public override XPathNodeType NodeType 
    { 
       get 
       {
       switch (state.Node) 
          {
             case NodeTypes.Root :
                 return XPathNodeType.Root;
              case NodeTypes.Element :
                   return XPathNodeType.Element;
              case NodeTypes.Attribute :
                  return XPathNodeType.Attribute;
              case NodeTypes.Text :
                  return XPathNodeType.Text;
           }
           return XPathNodeType.All;
           }
     }
     public override string LocalName 
     {
         
         get 
         {
             nametable.Add(Name);
             return nametable.Get(Name); 
         }
     }

     public override string Name 
       { 
         get 
           { 
             switch (state.Node)
           {
             case NodeTypes.Text :
                  return state.TextValue;
              case NodeTypes.Attribute :
                  return state.AttributeText;
              case NodeTypes.Element :
                   return state.ElementText;
               default :
                   return String.Empty;
                   
            }
        }
     }
     public override string NamespaceURI 
       {
        get 
        {
              return nametable.Get(String.Empty); 
           }
      }
      
      public override string Prefix 
       {
          get { return nametable.Get(String.Empty); }
       }
         public override string Value
      {
          get { 
               return state.TextValue;
                }
      }
      public override String BaseURI 
      {
          get { return String.Empty; } 
      }
      public override bool IsEmptyElement
      {
          get 
         {
             if(state.ElementType == 1) 
                return true;
           else 
               return false;
      }
      }
      
      public override string XmlLang
      {
         get{return "en-us";}
      }
      
      public override XmlNameTable NameTable 
      {
        get 
         { 
            return nametable; 
        }
      }
  
//Attribute Accessors

      public override bool HasAttributes 
      {
         get
         {
             if((state.Node != NodeTypes.Root) && (state.Node != NodeTypes.Attribute) && (state.Node != NodeTypes.Text))
                 return true;
             else
               return false;
      }
      }
      public override string GetAttribute( string localName, string namespaceURI ) 
        {
            if( HasAttributes)
            {
                int i;
                for(i = 0; i <  NumberOfAttributes[state.ElementType]; i++)
                {
                    if( AttributeIds[state.ElementType][i] == localName )
                        break;
                }

                if( i < NumberOfAttributes[state.ElementType] )
                {
                int TempAttribute = state.Attribute;
                NodeTypes TempNodeType  = state.Node;
                state.Attribute = i;
                state.Node = NodeTypes.Attribute;
                String AttributeValue = state.TextValue;
                state.Node =  TempNodeType;
                state.Attribute = TempAttribute;
                return AttributeValue;
                }
            }
            return String.Empty;
        }

        public override bool MoveToAttribute( string localName, string namespaceURI ) 
        {
            if( state.Node == NodeTypes.Attribute )
                MoveToElement();
            if( state.Node == NodeTypes.Element )
            {
                int i;
                for(i = 0; i < AttributeCount; i++)
                    if( AttributeIds[state.ElementType][i] == localName )
                    {
                        state.Attribute = i;
                        state.Node      = NodeTypes.Attribute;
                        return true;
                    }
            }
            return false;
        }

        public override bool MoveToFirstAttribute() 
        {
            if( state.Node == NodeTypes.Attribute )
                MoveToElement();
            if( AttributeCount > 0 )
            {
                state.Attribute = 0;
                state.Node = NodeTypes.Attribute;
                return true;
            }
            return false;
        }
        public override bool MoveToNextAttribute() 
        {
            
            int TempAttribute = -1;
            if( state.Node == NodeTypes.Attribute )
            {
                TempAttribute = state.Attribute;
                MoveToElement();
            }
            if( (TempAttribute + 1) < AttributeCount )
            {
                state.Attribute = TempAttribute + 1;
                state.Node = NodeTypes.Attribute;
                return true;
            }
            state.Node = NodeTypes.Attribute;
            state.Attribute = TempAttribute;
            return false;
        }

        //Namespace Accesors
        public override string GetNamespace(string localname)
        {
            return String.Empty;
        }
        public override bool MoveToNamespace(string Namespace)
        {
            return false;
        }

        public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope)
        {
            return false;
        }

        public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope)
        {
            return false;
        }
        
//Tree Navigation
    
        public override bool MoveToNext() 
        {
            int NextElement = IndexInParent + 1;
            FileSystemNavigator TempState = (FileSystemNavigator) this.Clone();
            if ( MoveToParent() )
            {
                if( MoveToChild(NextElement) )
                    return true;
            }
            this.state = new NavigatorState(TempState.state);
            return false;
        }
        
        public override bool MoveToPrevious() 
        {
            int NextElement = IndexInParent - 1;
            FileSystemNavigator TempState = (FileSystemNavigator) this.Clone();
            if ( MoveToParent() )
            {
                if( MoveToChild(NextElement) )
                    return true;
            }
            this.state = new NavigatorState(TempState.state);
            return false;
        }

        public override bool MoveToFirst() 
        {
            FileSystemNavigator TempState = (FileSystemNavigator) this.Clone();
            if ( MoveToParent() )
            {
                if( MoveToChild(0) )
                    return true;
            }
            this.state = new NavigatorState(TempState.state);
            return false;

        }
        public override bool MoveToFirstChild() 
        {
            FileSystemNavigator TempState = (FileSystemNavigator) this.Clone();
            if( MoveToChild(0) )
                return true;
            this.state = new NavigatorState(TempState.state);
            return false;
        }
    
        public override bool MoveToParent() 
        {
            switch(state.Node)
            {
                case NodeTypes.Root: 
                    return false;
                default:
                    if( state.Root != state.Doc.FullName )
                    {
                        if( state.Doc is DirectoryInfo )
                            state.Doc = ((DirectoryInfo) state.Doc).Parent;
                        else if( state.Doc is FileInfo )
                            state.Doc = ((FileInfo) state.Doc).Directory;
                        state.Node = NodeTypes.Element;
                        state.Attribute = -1;
                        state.ElementType = 0;
                        if( state.Root != state.Doc.FullName )
                        {
                            FileSystemInfo[] FileSystemEnumerator = ( ((DirectoryInfo) state.Doc).Parent).GetFileSystemInfos();
                            for(int i = 0; i < FileSystemEnumerator.Length; i++ )
                        {
                                if( FileSystemEnumerator[i].Name == state.Doc.Name )
                                {
                                state.ElementIndex = i;
                                }
                            }
                        }
                        else
                        {
                            state.ElementIndex = 0;
                        }
                        return true;
                    }
                    else
                    {
                        MoveToRoot();
                        return true;
                    }

        
            }
        }


        public override void MoveToRoot()
        {
            state.Node=NodeTypes.Root;
            state.Doc    = new FileInfo(state.Root);
            state.Attribute    = -1;
            state.ElementType  = -1;
            state.ElementIndex = -1;
        }
        public override bool MoveTo( XPathNavigator other ) 
        {
            if( other is FileSystemNavigator )
            {
                this.state = new NavigatorState( ((FileSystemNavigator) other).state);
                return true;
            }
            return false;
            }
        public override bool MoveToId( string id ) 
        {
            return false;
        }


        public override bool IsSamePosition( XPathNavigator other ) 
        {
            if( other is FileSystemNavigator )
            {
                if( state.Node == NodeTypes.Root )
                {
                    return (((FileSystemNavigator) other).state.Node == NodeTypes.Root);
                }
                else
                {
                    return (state.Doc.FullName == ((FileSystemNavigator) other).state.Doc.FullName);
                }
            }
            return false;
    
        
        }
    
        public override bool HasChildren 
        {
            get 
            { 
                return (ChildCount > 0); 
            }
        }
        


/***************Helper Methods*****************************************/
    
        //This is a helper method. Move the XPathNavigator from an attribute 
      // to its associated element.
        public bool MoveToElement() 
        {
            state.Attribute = -1;
            state.Node      = NodeTypes.Element;
            if ( state.Doc is DirectoryInfo )
                state.ElementType = 0;
            else 
                state.ElementType = 1;
            return true;
        }
        //Gets the index of this node if it is an element or the index of
      // the element node associated with the attribute.
        public int IndexInParent 
        {
            get 
            { 
                return state.ElementIndex; 
            }
        }
    

        
        //Helper method. Move to child i of the current node.
        public bool MoveToChild( int i ) 
        {
            if( i >= 0 )
            {
                    if( state.Node == NodeTypes.Root && i == 0)
                {
                    state.Doc = Directory.CreateDirectory(state.Root);
                    state.ElementType = 0;
                    if( !state.Doc.Exists )
                    {
                        FileStream tempStream = File.Open(state.Root,System.IO.FileMode.OpenOrCreate);
                        tempStream.Close();
                        state.Doc = new FileInfo(state.Root);
                        state.ElementType = 1;

                    }
                    state.Node = NodeTypes.Element;
                    state.Attribute = -1;
                    state.ElementIndex = 0;
                    return true;
                }
                else if( state.Node == NodeTypes.Element && state.ElementType == 0 )
                {
                
                    FileSystemInfo[] DirectoryEnumerator = ( (DirectoryInfo) state.Doc).GetFileSystemInfos();
                
                    if( i < DirectoryEnumerator.Length )
                    {
                        state.Node = NodeTypes.Element;
                        state.Attribute = -1;
                        state.ElementIndex = i;
                        if( DirectoryEnumerator[i] is DirectoryInfo)
                        {
                                state.Doc = DirectoryEnumerator[i];
                                state.ElementType = 0;
                        }
                        else if( DirectoryEnumerator[i] is FileInfo)
                        {
                            state.Doc = DirectoryEnumerator[i];
                            state.ElementType = 1;
                        }
                        return true;
                    }
                }
            }
            return false;
        }
        
        //returns the number of attributes that the current node has
        public int AttributeCount 
        {
            get 
            { 
                if( state.Node != NodeTypes.Root )
                {
                    return NumberOfAttributes[state.ElementType];
                }
                return 0;
            }
        }
        //Helper method. Returns the number of children that the current node has.
        public int ChildCount 
        {
            get 
            { 
                switch(state.Node)
                {
                    case NodeTypes.Root: 
                        return 1;
                    case NodeTypes.Element:
                        if( state.ElementType == 0 )
                        {
                            return (((DirectoryInfo) state.Doc).GetFileSystemInfos()).Length;
                        }
                        return 0;
                    default:
                        return 0;
                }
            }
        }
    
        //This class keeps track of the state the navigator is in.
        internal class NavigatorState
        {
            //Represents the element that the navigator is currently at.
            public FileSystemInfo doc;
            //The directory or file at the top of the tree
            String root;
            //The type of attribute that the current node is. -1 if the
         // navigator is not currently positioned on an attribute.
            public int attribute;
            //elementType of 0 is a directory and elementType of 1 is a file
            public int elementType;
            public int elementIndex;
            //The type of the current node
            public NodeTypes node;

            public NavigatorState(FileSystemInfo document)
            {
                Doc          = document;
                Root         = doc.FullName;
                Node         = NodeTypes.Root;
                Attribute    = -1;
                ElementType  = -1;
                ElementIndex = -1;
        
            }

            public NavigatorState(NavigatorState NavState)
            {
                Doc          = NavState.Doc;
                Root         = NavState.Root;
                Node         = NavState.Node;
                Attribute    = NavState.Attribute;
                ElementType  = NavState.ElementType;
                ElementIndex = NavState.ElementIndex;
        
            }

            public FileSystemInfo Doc
            {
                get 
                {
                    return doc;
                }
                set 
                {
                    doc = value;
                }
            }
    
            public String Root
            {
                get 
                {
                    return root;
                }
                set 
                {
                    root = value;
                }
            }

            public int Attribute
            {
                get 
                {
                    return attribute;
                }
                set 
                {
                    attribute = value;
                }
            }

            public int ElementType
            {
                get 
                {
                    return elementType;
                }
                set 
                {
                    elementType = value;
                }
            }

            public int ElementIndex
            {
                get 
                {
                    return elementIndex;
                }
                set 
                {
                    elementIndex = value;
                }
            }


            public NodeTypes Node
            {
                get 
                {
                    return node;
                }
                set 
                {
                    node = value;
                }
            }
            //Returns the TextValue of the current node
            public String TextValue
            {
                get 
                {
                    switch(Node)
                    {
                        case NodeTypes.Root :
                            return null;
                        case NodeTypes.Element : 
                            return null;
                        case NodeTypes.Attribute :
                            if( ElementType == 0 )
                            {
                                DirectoryInfo dInfo = (DirectoryInfo ) Doc;
                                switch(Attribute)
                                {
                                        case 0: return dInfo.Name;
                                        case 1: return dInfo.CreationTime.ToString();    
                                    }
                                }
                            else if( ElementType == 1 )
                            {
                                FileInfo fInfo = (FileInfo ) Doc;
                                switch(Attribute)
                                {
                                    case 0: return fInfo.Name;
                                    case 1: return (String) fInfo.CreationTime.ToString();
                                    case 2: return (String) fInfo.Length.ToString();
                                }
                            }
                            break;
                        case NodeTypes.Text :
                            return null;
                    }
                    return null;
                }
            }
            //returns the value of the attribute
            public String AttributeText
            {
                get 
                {
                    if( Node == NodeTypes.Attribute )
                        return AttributeIds[ElementType][Attribute];
                    return null;
                }
            }
            //Returns the name of the element.
            public String ElementText
            {
                get 
                {
                    return doc.Name;
                }
            }

        }
    }

Siehe auch

Der XPathNavigator in .NET Framework