XML-Datei: Bereiche Ersetzen (_StringBetween?)

  • Hey!
    Ich würde gerne in einer XML-Datei bestimmte Bereiche ersetzen.
    Die Datei sieht im Groben so aus:

    Zitat

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <TEST1>
    <TEST2>
    <TEST3 cat="xt4"/>
    </TEST2>
    </TEST1>

    Ich habe probiert mit _StringBetween nach dem Bereich zwischen cat=" und "/> zu suchen und diesen zu ersetzen.
    Leider klappt dies nicht einmal ansatzweise.
    Daher wäre es wirklich super, wenn ihr mir ein kleines Beispiel dafür liefern könntet.
    Datei einlesen --> Bereiche individuell ersetzen --> Datei abspeichern

  • [autoit]

    $sConfig = FileRead('tbl.xml')
    $aArray1 = _StringBetween($sConfig, "var", "/>")
    _ArrayDisplay($aArray1)

    [/autoit]


    Eine von vielen weiteren, gescheiterten Varianten...

  • Hallo Korby,

    dein Skript passt nicht zum geposteten Auszug aus #1, daher Beispiel auf #1 aufbauend (ich kenn den Inahlt der anderen Datei ja nicht.

    Spoiler anzeigen
    [autoit]

    #include <String.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $aString = _StringBetween('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'&@CrLf&'TEST1>'&@crlf&'<TEST2>'&@CRLF&'<TEST3 cat="xt4"/>'&@CRLF&'</TEST2>'&@CRLF&'</TEST1>','cat="', '"/>')
    MsgBox(0,"StringBetween ist",$aString[0])

    [/autoit]

    mfg (Auto)Bert

  • Gibt es keine Möglichkeit $sString automatisch einlesen zulassen?
    Ich möchte die durch _StringBetween ermittelten Bereiche anschließend ja auch durch andere ersetzen.

  • Hallo Korby,

    $aString = Array das die Ergebnisse von _StringBetween zugewiesen bekommt. Das einlesen kannst du ja so machen wie du es gepostet hast. Da du aber ganz andere Start- und Stopstring angegeben hast, gehe ich davon aus das in #1 nur ein Beispiel-XML stand. Falls du aber als Ergebnis xt4 erhalten willst dann sieht die Lösung so aus

    Spoiler anzeigen
    [autoit]

    #include <String.au3>
    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $sConfig = FileRead('tbl.xml')
    $aArray1 = _StringBetween($sConfig, 'cat="', '"/>)
    _ArrayDisplay($aArray1)

    [/autoit]


    nicht getestet (online geschrieben), sollte aber klappen

    mfg (Auto)Bert

  • [autoit]

    $sConfig = FileRead('tbl.xml')
    $aArray1 = _StringBetween($sConfig, 'cat=' & chr(34), chr(34) & '/>')
    _ArrayDisplay($aArray1)

    [/autoit]


    Damit funktioniert's.
    Gibt es jetzt noch eine einfache Methode, welche das Ersetzen dieser Stellen erlaubt?

  • Hallo Korby,

    ja schau dir dazu

    Zitat

    StringReplace
    --------------------------------------------------------------------------------

    Ersetzt ein oder mehrere Zeichen in einer Zeichenfolge.


    StringReplace ( "string", "searchstring", "replacestring" [, count [, casesense]] )

    mfg (Auto)Bert

  • Genau, aber dabei gibt es ein Problem.
    _StringBetween erstellt bei $Array[0] nicht die Anzahl der Einträge.
    Daher weiß ich nicht wie oft eine For-To-Schleife durchlufen werden muss.

  • Hallo Korby,

    die Anzahl der Einträge könntest du zwar mit UBound ermitteln, aber das brauchst du gar nicht. Wenn du als count 0 angibst werden alle ersetzt,

    mfg (Auto)Bert

  • Hallo Korby,

    teste das Beispiel in der Hilfe zu Stringreplace und du wirst sehen wie einfach das geht. Übrigens der Parameter Count ist dort optional und ist mit 0 vorbelegt. Du brauchst kein _Stringbetween (höchstens zur Kontrolle zusammen mit _ArrayDisplay), hatte vorhin zu oberflächlich gelesen und mich auf _StrinBetween eingeschossen, sorry,

    mfg (Auto)Bert

    • Offizieller Beitrag

    Alternativ geht auch StringRegExp():

    [autoit]

    $test = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' & @CRLF & _
    '<TEST1>' & @CRLF & _
    '<TEST2>' & @CRLF & _
    '<TEST3 cat="xt4"/>' & @CRLF & _
    '</TEST2>' & @CRLF & _
    '</TEST1>'

    [/autoit][autoit][/autoit][autoit]

    $search = StringRegExp($test, 'cat="([^"]+)"/', 1)
    If IsArray($search) Then
    MsgBox(0, '', 'Found: ' & $search[0])
    Else
    MsgBox(0, '', 'Kein Inhalt gemäß Muster')
    EndIf

    [/autoit]
  • Danke für Deine Antwort BugFix!
    Das Auslesen habe ich inwzischen gut geregelt.
    Doch ich finde keine "elegante" Möglichkeit Die einzelnen Werte zu ersetzen, jemand eine Idee?

    • Offizieller Beitrag

    Doch ich finde keine "elegante" Möglichkeit Die einzelnen Werte zu ersetzen, jemand eine Idee?


    Das geht "elegant" mit StrRegExpReplace().
    Sag nochmal genau was eingelesen wird (bzw. wie dieser Text aussehen kann, sicher unterschiedlich) und was am Ende übrig bleiben soll. Dann schau ich mal, dass ich dir das in ein schönes RegExp packe. :D

  • Alles klar :)
    Der Basis sieht momentan wie folgt aus:

    settings.xml

    (Werte werden später entschlüsselt)

    Nun möchte ich gezielt alle Attribute (value) mit neuen Werten belegen.
    Kurz und knackig :) Falls noch Fragen offen sind - Schieß los.

  • hi...

    also so mache ich das immer ....

    [autoit]

    #cs ----------------------------------------------------------------------------

    [/autoit][autoit][/autoit][autoit]

    AutoIt Version: 3.3.0.0
    Author: chrisatack

    [/autoit][autoit][/autoit][autoit]

    Script Function:
    Template AutoIt script.

    [/autoit][autoit][/autoit][autoit]

    #ce ----------------------------------------------------------------------------
    #include <array.au3>
    #include <file.au3>

    [/autoit][autoit][/autoit][autoit]

    Dim $array[1]
    _FileReadToArray ( @ScriptDir&'\test.xml',$array )
    ;~ _ArrayDisplay ( $array )

    [/autoit][autoit][/autoit][autoit]

    For $i = 1 To $array[0]-1

    If StringInStr ( $array[$i] , '499A844EOSJ40 value="' ) Then
    $now = StringSplit ( $array[$i],'"' )
    $array[$i] = $now[1]&InputBox('Neuer Wert','Wert für "499A844EOSJ40"', '111111111' )&$now[3]
    EndIf
    If StringInStr ( $array[$i] , '2E2345B37DE50 value="' ) Then
    $now = StringSplit ( $array[$i],'"' )
    $array[$i] = $now[1]&InputBox('Neuer Wert','Wert für "2E2345B37DE50"', '222222222' )&$now[3]
    EndIf
    If StringInStr ( $array[$i] , 'ZD8BF85F64 value="' ) Then
    $now = StringSplit ( $array[$i],'"' )
    $array[$i] = $now[1]&InputBox('Neuer Wert','Wert für "ZD8BF85F64"', '33333333' )&$now[3]
    EndIf
    ;..... usw
    Next

    [/autoit][autoit][/autoit][autoit]

    _FileWriteFromArray ( @ScriptDir&'\test_out.xml', $array, 1 )

    [/autoit]

    MFG chris :D

    • Offizieller Beitrag

    Nun möchte ich gezielt alle Attribute (value) mit neuen Werten belegen.

    Ja, schön und gut ==> entscheidend ist doch Welchen Wert möchtest du Womit ersetzen?
    Du brauchst doch einen Ansatz, z.B.: in <Category3> ersetze value Nr. 2 mit 'XYZ'. Woher kommen die Werte? Ein Array oder Input oder....?

  • Die Werte kommen aus einem Input.
    So kann man z.B. das Attribut von Root/Category1/2E2345B37DE50 einzeln ersetzen, genau wie alle anderen.
    In das Eingabefeld wird nur der entsprechende Wert eingetragen.

    • Offizieller Beitrag

    Geht leider nicht in einem Rutsch, aber geht:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    Local $inCategory = 'Category3'
    Local $inKey = '33XDA377C'
    Local $replValue = 'ABCDEFGHIJK'

    [/autoit] [autoit][/autoit] [autoit]

    Local $text = _
    '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' & @CRLF & _
    '<Root>' & @CRLF & _
    '<Category1>' & @CRLF & _
    '<499A844EOSJ40 value="9OAIBF9849574EB4240AB2ASD18DE9EF03605BB14C639541ECF721A6B8B4C6"/>' & @CRLF & _
    '<2E2345B37DE50 value="A8ASD3CA6E22E5B2242E61CDE1EAASDF97CB56C1565D03CE50DASF968428AS6"/>' & @CRLF & _
    '</Category1>' & @CRLF & _
    @CRLF & _
    '<Category2>' & @CRLF & _
    '<ZD8BF85F64 value="46FB045CD8B7GFF85E6BCDA5D382SAD922FFDA40F85FA9F92"/>' & @CRLF & _
    '</Category2>' & @CRLF & _
    @CRLF & _
    '<Category3>' & @CRLF & _
    '<ADO4B1AS4B3C value="48594229B26143B12B3C5C3C7CE11B46F67EA7C6A375C7CE"/>' & @CRLF & _
    '<33XDA377C value="D2656ED543F36DB3D7C5B5456700AA876924E8D8975AEAA9"/>' & @CRLF & _
    '<2A731C3ASDB7 value="9640EAD3A1C3DE39455F5C2D70554D2798D0B5A63999C8EF"/>' & @CRLF & _
    '</Category3>' & @CRLF & _
    '</Root>'

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $patternCategories = '<(?:Category\d+)>\r\n(?:<(?:[\w\d]+)\s+value="(?:[\w\d]+)"/>\r\n)*(?:</Category\d+>)(?:\r\n)+'
    Local $patternDetail = '<[\w\d]+\s+value="[\w\d]+"/>'
    Local $patternReplace = '(<)(' & $inKey & ')(\s+value=")([\w\d]+)("/>)'

    [/autoit] [autoit][/autoit] [autoit]

    ; Match auf alle Categories, je Category ein Arrayelement
    Local $MatchCat = StringRegExp($text, $patternCategories, 3)

    [/autoit] [autoit][/autoit] [autoit]

    ; innerhalb gesuchter Categorie alle key=value -Paare selektieren
    Local $aPair
    For $i = 0 To UBound($MatchCat) -1
    If Not StringInStr($MatchCat[$i], $inCategory) Then ContinueLoop
    $aPair = StringRegExp($MatchCat[$i], $patternDetail, 3)
    ExitLoop
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Schlüssel suchen und Wert ersetzen
    Local $sTmp = '<' & $inCategory & '>'
    For $j = 0 To UBound($aPair) -1
    If StringRegExp($aPair[$j], $patternReplace) Then
    $aPair[$j] = StringRegExpReplace($aPair[$j], $patternReplace, '$1$2$3' & $replValue & '$5')
    EndIf
    $sTmp &= $aPair[$j] & @CRLF
    Next
    ; korrigierten String zurückschreiben in Categorie
    $MatchCat[$i] = $sTmp & '</' & $inCategory & '>' & @CRLF

    [/autoit] [autoit][/autoit] [autoit]

    ; alle Categories zurückschreiben
    $sTmp = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' & @CRLF & '<Root>' & @CRLF
    For $i = 0 To UBound($MatchCat) -1
    $sTmp &= $MatchCat[$i] & @CRLF
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; zurückschreiben in Datei - hier in Console
    ConsoleWrite($sTmp & @CRLF & '</Root>' & @CRLF)

    [/autoit]