Funktion erstellen welche Text analysiert und einzelne Werte in Variable abfüllt

  • Hallo

    Leider muss ich mich als weitestgehend unerfahren hinsichtlich Programmierung outen und benötige Hilfe.
    Vor lauter Bäume sehe ich den Wald nicht mehr :(
    Ich verstehe nicht wie ich meiner Funktion beibringen kann im setting.xml File nach dem Wert der Variable zu suchen, anschliessend den Wert von
    Host Port und im dritten Schritt den Wert Host IP auszulesen resp. in Variablen abzufüllen.

    • im ersten Schritt lese ich einen Registry Key aus und belege damit eine Variable $MM_LastPopUsed

    Global $MM_LastPopUsed = RegRead("HKEY_CURRENT_USER\Software\Vendor\Prod\Platform", "LastPopIdUsed") --> hat bspw. Wert = ID_1 (kann aber auch ID_2 / ID_3 etc. sein)

    • anschliessend versuche ich eine Funktion zu erzeugen welche

      • 1. den Inhalt von $MM_LastPopUsed (also ID_1) im setting.xml File sucht, danach
      • 2. wenn dieser String ID_1 vorhanden/gefunden ist, den dazugehörigen Wert von <Hosts port="4444">
      • 3. den nachfolgenden Wert von <Host ip="Servermain"/> ausliest

    letztendlich benötige ich zwei abgefüllte Variablen mit den Werten des Ports und der Host IP (also 4444 und Servermain als Beispiel)


    Auszug aus dem setting.xml File

    <?xml version="1.0" encoding="utf-8" standalone="no"?>
    <Configuration>
    <AppSettings>
    <DefaultPop pop_id="Id_3"/>
    <Pops>
    <Pop name="ServerA" id="Id_3" source="User">
    <Hosts port="4555">
    <Host ip="servera"/>
    </Hosts>
    </Pop>
    <Pop name="ServerB" id="Id_2" source="User">
    <Hosts port="5555">
    <Host ip="Server"/>
    </Hosts>
    </Pop>
    <Pop id="Id_1" name="ServerMain" source="User">
    <Hosts port="4444">
    <Host ip="Servermain"/>
    ...............
    ................................


    Meine Versuche der Funktion sind bisher kläglich gescheitert, ich verstehs einfach noch nicht und die Hilfe verwirrt mich noch mehr ?(


    func _File_Read_XML_PORT-Host()

    Local $line = FileRead($file)
    if StringInStr ( $line, “$MM_LastPopUsed ") > 0 Then
    $posStart=StringInStr ( $line, $sPoPIst) + 11
    $posEnd=StringInStr ( $line, " id" , 0, 1) -1
    $sPoPIst=StringMid ( $line, $posStart , $posEnd - $posStart )
    MsgBox(0, "Pop Ist", "Name ist" & $sPoPIst )
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $strDefaultPop = ' & $sPoPIst & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    EndIf


    Ich bin mir durchaus bewusst das ich nicht erwarten kann eine Schlüsselfertige Lösung präsentiert zu erhalten, es würde mich aber sehr freuen
    wenn ich den einen oder anderen Tipp erhalten würde, welcher mir erklären würde wie ich das lösen kann.
    Besten Dank und Gruss
    Thork

  • Bei den Klaren Vorgaben ist ein RegEx sicher die schnellste/einfachste Lösung :)

    AutoIt
    #include <array.au3>
    $sFileData='<?xml version="1.0" encoding="utf-8" standalone="no"?>'&@crlf&'<Configuration>'&@crlf&'<AppSettings>'&@crlf&'<DefaultPop pop_id="Id_3"/>'&@crlf&'<Pops>'&@crlf&'<Pop name="ServerA" id="Id_3" source="User">'&@crlf&'<Hosts port="4555">'&@crlf&'<Host ip="servera"/>'&@crlf&'</Hosts>'&@crlf&'</Pop>'&@crlf&'<Pop name="ServerB" id="Id_2" source="User">'&@crlf&'<Hosts port="5555">'&@crlf&'<Host ip="Server"/>'&@crlf&'</Hosts>'&@crlf&'</Pop>'&@crlf&'<Pop id="Id_1" name="ServerMain" source="User">'&@crlf&'<Hosts port="4444">'&@crlf&'<Host ip="Servermain"/>'
    $MM_LastPopUsed="Id_1"
    $arResult=StringRegExp($sFileData,'(?s)<Pop(?:.*?)id="'&$MM_LastPopUsed&'"(?:.*?)>(?:.*?)<Hosts(?:.*?)port="(.*?)"(?:.*?)>(?:.*?)<Host(?:.*?)ip="(.*?)"(?:.*?)>',1)
    _ArrayDisplay($arResult)
    msgbox(48,"","IP: "&$arResult[1]&" Port: "&$arResult[0]&@crlf)
  • Hey @Thorkfumble

    Wenn du nicht einfach Kanashius Code nutzen, sondern das auch selbst machen möchtest, kommst du wahrscheinlich erst einmal leichter mit _StringBetween klar. Dafür musst du keine regulären Ausdrücke und StringRegExp beherrschen. Das ist auf jeden Fall der eleganteste Weg, von dem ich dich nicht abhalten will.
    Hier jedoch ein für Anfänger vllt. einfacher nachvollziehbares aber umständliches Beispiel:

    Grüße autoiter

  • Vorsicht, @autoiter !
    Die Reihenfolge bei XML-Elementen muss nicht immer gleich sein!
    Bei den Bespieldaten von Thorkfumble kann zum Beispiel schon ein Problem mit dem Pop und der ID entstehen, da das nicht immer direkt hintereinander steht:
    <Pop name="ServerB" id="Id_2" source="User">
    <Pop id="Id_1" name="ServerMain" source="User">

    Local $aPopIDs = _StringBetween($sString, 'Pop id="', '"') würde Id_2 nicht finden...

  • Ah, danke dir Kanashius. Da hast du natürlich recht!
    Ich habe einfach den Bereich mit den rot markierten Einträgen kopiert und verdoppelt, statt mir das ganze BSP zu nehmen.

    Auch für mein neues Bsp habe ich einen Eintrag erfunden. Ein schließendes </Pop>, das aber aigentlich auch wirklich vorhanden sein sollte.

    Grüße autoiter

  • Hallo
    Besten Dank für die Vorschläge, leider - so denke ich mal - sind diese beiden nicht wirklich umsetzbar oder ich versteh den Lösungsansatz nicht.

    Meine Ausgangslage ist ja, dass ich aus der Registry die ID_nn kenne und diese als Variable im script deklariert habe
    Global $MM_LastPopUsed = ID_nn

    Das settings.xml File wird diese ID_nn irgendwo beinhalten,ich benötige dann nur noch die Werte der beiden folgenden Tags <Host Port und <Host IP um diese weiterverarbeiten zu können.
    Was ich sagen kann ist, dass das xml File ID_nn sowie die beiden Tags Host Port und Host IP immer vorkommen.


    <Pop id="Id_1" name="ServerMain" source="User">
    < Hosts port="4444">
    < Host ip="Servermain"/>

    @autoiterdu gehst davon aus das es einen TAG <Pop> gibt was nicht der Fall ist,
    es beginnt mit <Pops> gefolgt von <Pop name> oder <Pop id> und schliesst mit </Pop> </Pops> .
    Ebenso deklarierst du eine Variable $sString mit dem Inhalt des xml files, ohne dass das File eingelesen wird.

    Mir scheint diese Sache ziemlich kompliziert daher verfolge ich alternativ einen zweiten Ansatz,weiss aber auch nicht wie dies in autoit umsetzbar wäre.

    Unter Unix würde ich netstat mit awk ausführen und dies einer Variablen zuordnen, etwa so:

    netstat -an | grep 4555
    TCP 10.156.1.34:50965 192.168.90.78:4555 ESTABLISHED

    netstat -an | grep 4555 |awk -F" " '{print $3}'
    192.168.90.78:4555

    oder etwas verfeinert

    netstat -an | grep 4555 |awk -F" " '{print $3}'|awk -F: '{print $1, $2}'
    192.168.90.78 4555

    Ich bekäme so alternativ zum Hostname die IP gelistet,was mir ausreichen würde.
    Nur will das auch nicht richtig klappen, untenstehende autoit Funktion gibt als Ergebniss die PID von cmd.exe aus.

    func _Get_Netstat_Port()
    Local $sData = Run('cmd /k netstat -an |find /n /i "4555"', '', @SW_SHOW)
    ;Local $sData = Run(@ComSpec & " /c " & 'netstat -an'|findstr 555' , @SW_HIDE)
    MsgBox (0, "titel", "text" & $sData)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $strDefaultPop = ' & $sData & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    EndFunc

    Was mache ich falsch?

    Vielen Dank für weitere Hilfe
    thork

  • Du kannst einfach das hier verwenden:

    AutoIt
    Local $sFileData = FileRead("datei.txt")
    $arResult=StringRegExp($sFileData,'(?s)<Pop(?:.*?)id="'&$MM_LastPopUsed&'"(?:.*?)>(?:.*?)<Hosts(?:.*?)port="(.*?)"(?:.*?)>(?:.*?)<Host(?:.*?)ip="(.*?)"(?:.*?)>',1)
    _ArrayDisplay($arResult)
    msgbox(48,"","IP: "&$arResult[1]&" Port: "&$arResult[0]&@crlf)

    Wir haben den Text nur in der Variable gespeichert, weil wir die Datei nicht haben/anlegen wollten. Du kannst irgendwas anderes in die Variable schreiben, also auch das ergebnis von FileRead. (Sind beides Strings, also Text)
    Danach wende ich ein RegEx an, um die beiden Werte einzulesen. Die stehen dann in einem Array, einer Art Liste, auf die man mit $variable[0],$variable[1],... zugreifen kann. So wie es in der msgbox auch gemacht wird.
    Somit kannst du hier einfach $host=$arResult[1] schreiben, und die Ip steht in der Variable. Beim FileRead einfach den Dateinamen eingeben.

    Was deinen anderen Versuch angeht: Natürlich bekommst du die PID von cmd, schließlich startest du ja auch ein cmd-prozess. (Drück mal F1 nachdem du Run angelickt (Cursor dort positioniert) hast. Dann erscheint die Hilfe zu der Funktion.
    Mit StdoutRead kannst du die Ausgaben der Konsole auslesen.

    MfG Kanashius

  • Hi @Thorkfumble,

    Es geht um das korrigierte Skript von 21:41?

    Ja, ich habe einfach eine Variable $sString deklariert, mit dem Inhalt, den du oben als Beispiel gepostet hast. Warum denn auch anders? Du müsstest natürlich die echte Datei einlesen. Das ginge einfach so:

    $sString = Fileread("Pfad_zur_Datei\setting.xml") <- Den Pfad zur Datei musst du natürlich eintragen. Mehr ist aber auch nicht notwendig und $sString ist bei dir genauso gefüllt.


    Schau mal das erste StringBetween an:

    AutoIt
    Local $aPops = _StringBetween($sString, '<Pop ', '</Pop>') ; Hier werden alle Elemente zwischen <Pop und </Pop> in ein Array gelesen.


    Da wird der String zwischen '<Pop ' und '</Pop>' ausgegeben (Also auch Pop Name...

    Füge doch mal folgende Zeile direkt unter der oben angegebenen ein, um dir direkt das erste Ergebnis anzuschauen:

    AutoIt
    _ArrayDisplay($aPops, "Strings zwischen '<Pop ' und '</Pop>'")


    Du siehst dann in dem Bsp. eine dreizelige Tabelle. Im Anschluss wollte ich daraus nur ein nettes Array zimmern, in dem du alle Einträge findest, um das zu veranschaulichen. War aber sicher nicht die beste Lösung von mir.


    Wenn du SciTE benutzt, dann klicke einfach auf einen Befehl und drücke die Taste F1. Dann öffnet sich die Hilfebeschreibung zu dem Befehl mit Beispielskripten.

    Grüße autoiter

  • Hallo Autoiter

    Besten Dank, habe endlich Zeit gefunden mir deinen Lösungsvorschlag durch den Kopf gehen zu lassen und erhalte nun eine saubere Auflistung aller Eintrage des xml Files :) !
    Der Ansatz mit Array erscheint mir sehr effiezient, weitaus effizienter als jedes Attribut aus dem Text rauszufriemeln.

    Zu guter letzt stelle ich mir aber die Frage, dass - wie Eingangs beschrieben - ich den aus der Registry ausgelesenen Wert (zBsp. $MM_LastPopUsed = ID_5) diesen im Array
    wieder finde und mir die Attributewerte aus Col1 und Col2 anzeigen resp. in neuen Variablen abfüllen lassen kann .

    Spoiler anzeigen


    Käme da _ArrayFindAll in Frage, was ich versucht aber nicht verstanden habe,
    oder kann das mit einem IF $MM_LastPopUsed EXIST; THEN ...... Statment in deine Funktion integriert werden?

    Fragen über Fragen..............mir raucht der Schädel ?(

    Gruss thork

  • Hallo @Thorkfumble,

    Unten habe ich noch einmal das Skript aus Beitrag 5. Diesmal habe ich dir auch die Ermittlung des gewünschten Elements eingefügt. Es handelt sich um die letzten Zeilen nach dem _ArrayDisplay($aResult).

    Da du hier auch nur ein Ergebnis brauchst, ist der Befehl _ArraySearch. (In dem Beispiel hatte ich ja nur 3 Ids. Du musst eine von diesen suchen ;) . Im Beispiel wird ID_2 gesucht.)

    Arrays sind eine wunderbare Geschichte. Zum besseren Verständnis kannst du das ganz tolle Tutorial von BugFix studieren: http://www.bug-fix.info/array_tut.htm

    Spoiler anzeigen

    Grüße autoiter

  • hi autoiter

    wenn ichs richtig verstehe müsste ich demnach nur ID_2 durch die $MM_LastPopUse variable ersetzen
    $iIndex = _ArraySearch($aResult, "ID_2") ;
    etwa so?
    $iIndex = _ArraySearch($aResult, &" $MM_LastPopUse" )

    ich werde morgen weiter experimentieren :)
    gruss thork

  • Guten Morgen @Thorkfumble,

    $iIndex = _ArraySearch($aResult, &" $MM_LastPopUse" )

    Das ist schon die richtige Stelle.
    Allerdings muss der Operator & da weg. Damit verknüpft man Zeichenketten. Es müsste also auch vor & eine Zeichenkette stehen.
    Außerdem müssen die Anführungszeichen da weg. Die markieren nämlich Beginn und Ende einer Zeichenkette, die kein AutoIt-Code ist. Das heißt, du suchst in dem Fall nicht nach dem Inhalt der Variable $MM_LastPopUse sondern genau nach diesen Zeichen.

    Hier ein Beispiel:

    Code
    Local $MM_LastPopUse = ID_1
    MsgBox(0, "", "Der Wert/Inhalt der Variable $MM_LastPopUse lautet: " & $MM_LastPopUse)

    Wenn du das ausführst siehst du vorne die Bezeichnung deiner Variable ($MM_LastPopUse) und hinten den Wert der Variable (ID_1).
    Die Zeile muss also so aussehen: $iIndex = _ArraySearch($aResult, $MM_LastPopUse)


    PS: Ich weiß nicht, ob du SciTE benutzt, rate es dir aber und empfehle dir auch die Hilfe darin. Fragen, die sich einem stellen, weil man die Sprache noch nicht kennt klären sich anhand der Erklärungen dort und der Beispiele die dort vorhanden sind. Die Beispiele kannst du alle ausführen und sie dir so direkt veranschaulichen lassen.

    Grüße autoiter

  • Hallo Autoiter & Kanashius

    Besten Dank für die Zeit die ihr meinem Problem resp. mir Unwissenden zu Teil kommen habt lassen.

    Letztendlich haben mir der Code und die dazugehörenden Instruktionen von autoiter sehr geholfen, einerseits das Problem zu lösen,
    anderseits zu verstehen wie autoit funzt.

    Besten Dank und Gruss an euch beide
    Thork