Hey, Scripting Guy!Autos nachjagen ... und XML

Die Scripting Guys von Microsoft

Laden Sie den Code für diesen Artikel herunter: HeyScriptingGuy2007_02.exe (150KB)

„KEINE AHNUNG, warum mein Hund immer hinter Autos nachjagt“, geht der alte Witz. „Was würde er machen, wenn er tatsächlich mal eins fängt?“

Gute Frage. Die Scripting Guys können sie auch nicht beantworten. Es sei denn Lucy, eine Hündin ein paar Häuser weiter, erwischt das Auto. Die würde nämlich sofort einen Schnapsladen überfallen und dann den Wagen als Fluchtauto missbrauchen. Wenn man sich den Rasen im Vorgarten ansieht, würde sie unterwegs auch nicht anhalten, um mal auszutreten. Wenn Sie wissen, was wir meinen.

Wenn wir diese altehrwürdige Geschichte an das Hightechzeitalter anpassen müssten, ginge sie in etwa so: „Ich weiß nicht, warum mein Systemadministrator immer wieder versucht, XML zu lernen. Denn was würde er damit anfangen, wenn er es irgendwann endlich geschafft hätte?“

Hinweis: Zu unserer Verteidigung: Wir haben ja nur gesagt, dass wir den Witz anpassen, aber nicht, dass man dann auch darüber lachen kann.

Ganz ehrlich gesagt: Das Thema „XML“ ist wahrscheinlich ein wenig aufgebauscht worden, zumindest dann, wenn es um Systemverwaltung geht. Die Wahrheit ist, dass viele Systemadministratoren auf ein langes und zufriedenes Leben zurückblicken können, ohne je ein Skript geschrieben zu haben, das mit einer XML-Datei interagiert hätte, und wir glauben auch nicht, dass sich das in naher Zukunft ändern wird.

Dabei darf man allerdings nicht vergessen, dass XML in immer mehr Anwendungen als Standard für die Speicherung von Daten zum Einsatz kommt. Warum auch nicht? Es handelt sich ja lediglich um aufgemotzte Textdateien. XML lässt sich schnell und einfach erstellen, kann plattformübergreifend verwendet werden und benötigt keine komplizierten und teuren Datenbankprogramme. Haben Sie ein Betriebssystem und einen Texteditor? Dann können Sie eine XML-Datenbank erstellen.

Das heißt im Umkehrschluss, dass Systemadministratoren für XML mindestens eine Verwendung haben: Sie können damit Skripts schreiben, die eine XML-Datei abfragen, als wäre diese Datei eine vollwertige Datenbank. Wer wäre besser dafür geeignet, Ihnen ein paar Tipps in dieser Angelegenheit zu geben, als die Scripting Guys?

Gutes Argument. Aber wenn wir raten müssten, würden wir wetten, dass Lucy höchstwahrscheinlich keine Zeit hat, einen Artikel über XML zu schreiben, weil sie unbedingt das Blumenbeet im Garten des Nachbarn durchwühlen muss.

Zunächst wollen wir uns eine einfache XML-Datei anschauen (siehe Abbildung 1), eine Datenbankdatei mit vier Skripts, die auch in der täglichen Rubrik Hey, Scripting Guy! vorkommen.

Figure 1 Hey, Scripting Guy! Skripts in XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Print a Microsoft Access Report?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1020.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Compact a Microsoft Access Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1009.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Word</Subcategory>
    <Keyword>hyperlinks</Keyword>
    <Title>How Can I Change an Existing Hyperlink in a Microsoft Word Document?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
  <Script>
    <Category>Enterprise Servers</Category>
    <Subcategory>Microsoft SQL Server</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Create a Table in a SQL Server Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
</Repository>

Wie Sie sehen, handelt es sich um eine ziemlich einfache, kleine Datei. Jedes einzelne Skript ist unter einem <Script>-Tag abgelegt. Ab sofort betrachten wir diese Skripts als Datensätze. Sie haben Recht: XML-Liebhaber würden diese Elemente nie als Datensätze bezeichnen. Aber das geht in Ordnung. Wir wollen Ihnen hier beibringen, wie Sie etwas, das Sie schon kennen (Abfragetechniken für Datenbanken), auf eine neue, andersartige Datenquelle anwenden. Wir haben uns gedacht, dass wir uns zuerst darauf konzentrieren, wie wir die Sache erledigen, und später wieder auf das Thema zurückkommen, um Ihnen die richtige Terminologie beizubringen.

Zurück zu den Datensätzen. Jeder Datensatz enthält die folgenden Felder: <Category> (Kategorie), <Subcategory> (Unterkategorie), <Keyword> (Schlüsselwort), <Title> (Titel) und <URL>.

Sie sind nicht ganz so beeindruckt, wie wir es gehofft hatten. Vielleicht hilft es Ihnen, wenn wir Ihnen ein Skript zeigen, mit dem sich diese XML-Datei öffnen und der Inhalt wiedergeben lässt:

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Scripts.xml")

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

Hinweis: Bei den Bezeichnungen der Tags ist zwischen Groß- und Kleinschreibung zu unterscheiden. Es muss heißen „/Repository/Script“ und nicht etwa „/repository/script“ oder „/REPOSITORY/SCRIPT“.

Klar, auch das ist nicht besonders beeindruckend. Aber darum geht es ja: Die ganze Angelegenheit ist nicht halb so kompliziert, wie Sie gedacht haben.

Wie Sie anhand des Codes erkennen können, erstellen wir erst einmal eine Instanz des Objekts „Microsoft.XMLDOM“, dem COM-Objekt, das für die Arbeit mit XML-Dateien verwendet wird. Danach ändern wir die Eigenschaft „Async“ in „False“. Dadurch wird gewährleistet, dass die gesamte Datei in den Speicher eingelesen wird, bevor das Skript wieder die Kontrolle übernimmt. Anschließend verwenden wir die Load-Methode, um die Datei „C:\Scripts\Scripts.xml“ zu lesen:

xmlDoc.Load("C:\Scripts\Scripts.xml")

Sobald die Datei in den Speicher geladen worden ist, können wir mithilfe der selectNodes-Methode die angegebenen Datensätze aus der Datenbank wählen:

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

Sehen Sie sich den Parameter näher an, der an selectNodes übergeben wurde. Es handelt sich dabei um den Pfad innerhalb der XML-Datei. Unsere XML-Datei hat die folgende Struktur:

<Repository>
    <Script>
        <Category></Category>
        <Subcategory></Subcategory>
        <Keyword></Keyword>
        <Title></Title>
        <URL></URL>
    </Script>
</Repository>

Ob Sie das interessieren sollte? Mit einem Wort: ja! Beim Umgang mit XML-Dateien ist die Struktur sehr wichtig. Wie ruft man beispielsweise die einzelnen Eigenschaften eines Datensatzes ab? Das ist einfach: Wir greifen auf das <Repository>-Tag zu, hinter dem das<Script>-Tag kommt, gefolgt von den einzelnen Eigenschaftstags. Wissen Sie was? Das ist derselbe Pfad, den wir selectNodes als Parameter übergegeben haben. Wir hängen dem Pfad einfach ein „/*“ an. Übersetzt heißt das: „Wähle alle Eigenschaften für diese Datensätze aus“. Mit anderen Worten: Die ausgegebene Sammlung besteht aus allen Eigenschaften für alle Datensätze in der Datenbank. Das ist so, als hätten Sie sich für die Abfrage „Select * From“ in Windows® Management Instrumentation (WMI) entschieden.

Hinweis: Probieren Sie das Beispielskript aus, dann wissen Sie genau, worauf wir hinauswollen.

Das restliche Skript ist leicht: Wir richten einfach nur eine For Each-Schleife ein, um die Sammlung durchzugehen und den Wert der Text-Eigenschaft für jedes Objekt und jede Eigenschaft wiederzugeben.

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

Das ist viel einfacher, als hinter Autos nachzujagen.

Aber Sie haben Recht: Wenn wir nur den gesamten Inhalt der Datei hätten wiedergeben wollen, hätten wir uns gar nicht um den ganzen XML-Kram kümmern müssen und nur FileSystemObject verwendet. (Das wäre vielleicht ein bisschen komplizierter gewesen, aber auch nur ein bisschen). Um Sie restlos vom Nutzen von XML zu überzeugen, müssen wir uns aber wahrscheinlich noch etwas mehr anstrengen.

Mal sehen, ob wir das hinkriegen. Im ersten Skript haben wir alle Eigenschaftenwerte für alle Datensätze bekommen. Das ist ja schön und gut, aber nehmen wir mal an, wir wollten einfach nur den Skripttitel haben! Geht das überhaupt?

Laut Lucy müssen wir nur unseren selectNodes-Befehl ändern, indem wir die Eigenschaft, die uns interessiert, an das Ende des Pfads stellen. Anders gesagt:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/Title")

Offensichtlich wurden beim ersten Mal alle Eigenschaften wiedergegeben, weil wir das Platzhalterzeichen „*“ verwendet haben. Jetzt erhalten wir nur die Title-Eigenschaft. Warum? Weil das der einzige Eigenschaftenwert ist, um den wir gebeten hatten.

Hinweis: Sehen Sie sich dies an: XML gibt Ihnen genau das, worum Sie gebeten haben. Sei nicht sauer, Lucy, aber es sieht so aus, als wäre jetzt XML der beste Freund des Menschen!

Sicher kann man mehr als eine Eigenschaft wiedergeben lassen! Dieser geänderte Befehl gibt z. B. Werte für die Title- und die URL-Eigenschaft wieder:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL)")

Zugegeben, die Syntax macht einen etwas unaufgeräumten Eindruck, aber man gewöhnt sich daran. Zunächst legen wir den übergeordneten Anteil des Pfads fest, genau wie eben:

    /Repository/Script/

Wir fügen dann einen Satz Klammern hinzu und tragen innerhalb der Klammern die Eigenschaften ein, die wiedergegeben werden sollen. Hinweis: Die Eigenschaften werden dabei durch das |-Zeichen getrennt. Anders gesagt:

    (Title | URL)

Es ist zwar ein bisschen albern, aber es funktioniert.

Sie müssen sich nicht auf die Wiedergabe von zwei Eigenschaften beschränken. Sie müssen nur darauf achten, genügend Trennzeichen einzufügen, dann bekommen Sie alle Informationen angezeigt, die Sie sich wünschen. Der nachfolgende Befehl gibt z. B. drei Eigenschaften wieder (Title, URL und Keyword):

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL |          Keyword)")

Aber Sie haben wieder Recht: Bis jetzt haben wir nur Informationen zu allen Datensätzen in unserer Datenbank abgerufen. Daran ist aber auch nichts auszusetzen. Oft will man nämlich genau das und nichts anderes. Aber es kommt auch vor (und das gar nicht so selten), dass wir nur Informationen über eine Teilmenge der Datensätze abrufen möchten. Das kann beispielsweise der Fall sein, wenn wir lediglich die Skripts herausfiltern wollen, die über ein Schlüsselwort (Keyword) verfügen, das gleich „databases“ ist. Also mit einer Abfrage, die dieser hier ähnelt:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]")

Wieder ist die Syntax ein wenig schräg. Aber sie hat auch einen Vorteil: Sie ist einfach und direkt. Nach der Angabe des übergeordneten Pfads stellen wir unsere Where-Klausel (z. B. „Wo ist X gleich Y?“) in eckige Klammern:

/Repository/Script [Keyword = ‘databases’]

Wie Sie wahrscheinlich bereits wissen, befiehlt unsere Where-Klausel dem Skript: „Gib nur die Elemente wieder, bei denen das Keyword-Attribut gleich ‘databases’ ist.“ Beachten Sie, das ‘databases’ in einfachen Anführungszeichen steht. Das geht nicht nur in Ordnung, es ist ein absolutes Muss. Wenn der Filterbegriff in doppelten Anführungszeichen steht, erhalten Sie nämlich einen Syntaxfehler, sobald Sie versuchen, das Skript auszuführen.

Hinweis: Warum? Weil die gesamte Abfragezeichenfolge – "/Repository/Script [Keyword = ‘databases’]" – in doppelte Anführungszeichen eingeschlossen ist.

Selbstverständlich müssen Sie sich beim Filtern der Daten nicht auf das Gleichheitszeichen (=) beschränken. Sie können Größer-als-Zeichen (>) oder Kleiner-als-Zeichen (<) verwenden sowie die allseits beliebten Kleiner-gleich-Zeichen (<=) oder Größer-gleich-Zeichen (>=). Sie können diese Zeichen auch negieren, indem Sie ihnen ein Ausrufezeichen voranstellen. Der folgende Befehl fordert beispielsweise alle Skripts an, bei denen das Schlüsselwort ungleich „databases“ ist (beachten Sie das „!=“):

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword != ‘databases’]")

Moment mal! Wer hat gesagt, dass man Filter setzen kann, aber bestimmt keinen Filter setzen und die wiederzugebenden Eigenschaften bestimmen kann? Klar geht das!

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]/Title")

Wenn alles gut läuft, wird durch diesen Befehl nur die Title-Eigenschaft für alle Skripts wiedergegeben, die über das Schlüsselwort „databases“ verfügen. Mal sehen, ob es funktioniert:

    How Can I Print a Microsoft Access Report?
    How Can I Compact a Microsoft Access Database?
    How Can I Create a Table in a SQL Server     Database?

Vielleicht können wir noch einen Befehl unterbringen, bevor wir für heute Schluss machen. Obwohl wir Fortschritte machen, bekommen wir vielleicht immer noch mehr Datensätze zurück, als wir eigentlich wollen. Schließlich gibt unser vorhergehender Befehl eine Mischung aus Microsoft® Access®- und Microsoft SQL Server™-Skripts wieder. (Warum? Weil alle diese Skripts das Schlüsselwort „databases“ verwenden.) Was ist, wenn wir die wiedergegebenen Daten auf Skripts beschränken wollen, die „databases“ als Schlüsselwort und „Microsoft SQL Server“ als Unterkategorie haben? Kann man vielleicht sogar nach mehreren Kriterien filtern?

Das müssen Sie doch gar nicht fragen:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’ and " & _
    "Subcategory = ‘Microsoft SQL Server’]")

Die Syntaxgrundlage ist dieselbe, wir haben nur zwei unterschiedliche Kriterien (nämlich Keyword = ‘databases’ und Subcategory = ‘Microsoft SQL Server’) verwendet und beide mit dem Operator UND verknüpft.

Hinweis: Ja, Sie haben Recht: Mit dieser einfachen kleinen XML-Datei hätten wir alle Skripts anfordern können, bei denen die Unterkategorie gleich „Microsoft SQL Server“ war. Aber das hätte keinen Spaß gemacht, und Sie hatten auch nicht so viel gelernt.

Sie können auch ODER-Klauseln verwenden. Stellen Sie sich beispielsweise vor, wir hätten jede Menge Microsoft Office-Skripts gehabt, einschließlich solcher, deren Unterkategorien „Microsoft Excel®“, „Microsoft Powerpoint®“, „Microsoft Outlook®“ und so weiter gewesen wären. Ist es möglich, die wiedergegebenen Daten auf die Skripts aus den Unterkategorien „Microsoft Word“ oder „Microsoft Access“ zu beschränken? Mit Sicherheit.

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Subcategory = ‘Microsoft Word’ " & _
    "or Subcategory = ‘Microsoft Access’]")

Sieht doch besser aus, oder? Zugegeben, dieser Artikel hat Ihr Leben sicherlich nicht revolutioniert, aber die Chancen stehen gut, dass Ihnen die Fähigkeit, auf diese Weise mit einer XML-Datei umzugehen, früher oder später zugute kommen wird. Denken Sie daran, Sie haben die Wahl: Wollen Sie grundlegende XML-Techniken lernen oder lieber Autos nachjagen? Das entscheiden Sie allein. (Wenn Sie sich für die letztgenannte Alternative entscheiden und zufälligerweise Lucy, die Hündin, auf der Straße treffen sollten, grüßen Sie sie doch bitte herzlich von den Scripting Guys. Sagen Sie ihr, sie soll sich von unserem Vorgarten fernhalten!)

Hey, Scripting Guy! – jeden Tag

Sie haben sich gerade die Monatsausgabe von „Hey Scripting Guy!“ durchgelesen und gedacht, dass das ja wohl die genialste technische Information sein muss, die Ihnen je unter die Augen gekommen ist. Vielleicht gehen Sie noch einen Schritt weiter und behaupten, dass es sich um das größte Schriftstück aller Zeiten handelt! Außerdem stehen Sie gerade ungeduldig neben Ihrem Postfach und warten auf die neue Ausgabe des TechNet Magazins, damit Sie noch mehr solche tollen Artikel lesen können.

Worauf warten Sie dann noch? Möchten Sie noch mehr über Lucy, die freundliche Hündin aus der Nachbarschaft oder die neuesten Heldentaten des Scripting Son erfahren? Bleiben Sie bei diesen „wichtigen“ Fragen einfach auf dem Laufenden, indem Sie die täglich erscheinenden Artikel aus der Rubrik „Hey, Scripting Guy!“ lesen. Von Montag bis Freitag (außer an Feiertagen und Urlaubstagen der Scripting Guys) erfahren Sie alles über Highschoolbaseball, Collegefootball und -basketball in den USA und können gelegentlich einen lokalen Wetterbericht abrufen. (Sicher ist der nur lokal, wenn Redmond für Sie lokal ist, aber eigentlich will doch jeder wissen, ob es in Redmond gerade regnet oder nicht, stimmt’s?)

Dann werden Sie auch noch jeden Tag etwas Neues über Skripting erfahren! Richtig, die Skriptinginformationen werden quasi in eine Flut packender Inhalte eingebettet. In jeder Ausgabe beantworten die Scripting Guys echte Fragen, die hoffentlich auch von echten Menschen gestellt wurden. Die Rubrik erscheint täglich online in englischer Sprache unter microsoft.com/technet/scriptcenter/resources/qanda. Da sie bereits hunderte von Fragen beantwortet haben, ist ihr Archiv ziemlich umfangreich und daher eine hervorragende Quelle für Skriptinginformationen (siehe microsoft.com/technet/scriptcenter/resources/qanda/hsgarch.mspx).

Sie haben eine Frage an die Scripting Guys? Schicken Sie sie an scripter@microsoft.com, und wenn Sie Glück haben, wird sie auch beantwortet! (Wenn Sie sie nicht abschicken, kriegen Sie garantiert keine Antwort. Sie haben also nichts zu verlieren. Im Unterschied zu einem Lottoschein kostet die Teilnahme nichts, und Ihre Chancen auf einen Hauptgewinn stehen etwas besser.)

Die Scripting Guys von Microsoft arbeiten für (und sind Angestellte von) Microsoft. Wenn sie nicht gerade ihrem Hobby, dem Baseball (oder verschiedenen anderen Aktivitäten) nachgehen, betreiben sie das TechNet Script Center. Besuchen Sie es unter www.scriptingguys.com.

© 2008 Microsoft Corporation und CMP Media, LLC. Alle Rechte vorbehalten. Die nicht genehmigte teilweise oder vollständige Vervielfältigung ist nicht zulässig.