Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit
GELÖST

Mittels Batch mehrere Einträge aus mehreren XML-Dateien in eine Textdatei schreiben

Frage Entwicklung Batch & Shell

Mitglied: tardezyx

tardezyx (Level 1) - Jetzt verbinden

29.04.2010, aktualisiert 22:38 Uhr, 7369 Aufrufe, 15 Kommentare

aus mehreren Dateien (identische Grammatik) mit unterschiedlichen Inhalten sollen mehrere Einträge an unterschiedlichen Positionen (aber innerhalb identischer Tags) in einer separaten neuen Datei übersichtlich gespeichert werden

Hallo,

eigentlich steht das Problem schon im Titel ;)

Ich habe mehrere tausend XML-Dateien, die der gleichen Grammatik folgen und würde gerne bestimmte Informationen daraus in eine einzige Textdatei schreiben, wobei die einzelnen Einträge mittels selbst definiertem Trennzeichen (Tabulator oder Semikolon ist erstmal egal - dient zum späteren Datenimport in Excel) in eine Zeile geschrieben werden sollen und für jede XML-Datei genau 1 Zeile belegt werden soll.

Die XML-Dateien befinden sich darüber hinaus in Unterordnern, so dass man die unterschiedlichen Pfade in den Batch-Aufruf integrieren müsste. Es ist mir aber bereits gelungen, sämtliche Pfade zu den .nfo-Dateien vorab in einer Datei mittels diesem Code abzulegen, der wiederum mittels der Datei list_all_nfos.bat gestartet wird (diese könnte man also in die Batch-Prozedur integrieren):

01.
dir /B /s *.nfo > nfo-list.txt
Die XML-Dateien seien wiederum wie folgt aufgebaut ("..." ist unwichtiges Zeugs):

01.
<?xml version="1.0" encoding="utf-8"?> 
02.
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
03.
  <title>Dies ist ein Titel</title> 
04.
  <year>2006</year> 
05.
  <durance>5.3</durance> 
06.
  <members>1,217</members> 
07.
  <lead>Alfred / Josef / Mike</lead> 
08.
  ... 
09.
  <extract> 
10.
    <details> 
11.
      <astate> 
12.
        <hidden>stealth</hidden> 
13.
        ... 
14.
      </astate> 
15.
      <vstate> 
16.
        <hidden>block</hidden> 
17.
        ... 
18.
      </vstate> 
19.
    </details> 
20.
  </extract> 
21.
</data>
Herauskommen soll hierbei die folgende Zeile (Tabulatorenabstand):

01.
Dies ist ein Titel	2006	5.3	Alfred / Josef / Mike	stealth	block
Danach soll automatisch ein Zeilenumbruch eingefügt und die nächste .nfo-Datei geparst werden, bis das Programm keine weiteren findet (also die nfo-list.txt am Ende angekommen ist).

Wichtig hierbei ist, dass die herauszuziehenden Informationen bei allen Dateien immer zwischen denselben Tags liegen (alle XML-Dateien unterliegen derselben Grammatik), d.h. der Titel liegt immer zwischen <title> und </title>, das Jahr immer zwischen <year> und </year> usw., aber wo sich diese Tags konkret befinden, ist von Datei zu Datei unterschiedlich, da sich jeweils eine weitere Menge an unterschiedlichen Informationen darin befinden. Außerdem kommen die meisten gesuchten Tags nur 1x pro Datei vor, d.h. es gibt nur einen Titel und nur ein Jahr usw., aber es gibt 2x den <hidden> & </hidden> Tag, so dass man dort den vorangehenden Tag mit einbeziehen müsste - also <astate> & <vstate>.


Wäre das überhaupt mittels Batch-Programmierung umzusetzen?

Danke und Gruß!
Mitglied: bastla
30.04.2010 um 00:15 Uhr
Hallo tardezyx und willkommen im Forum!

Soferne es in den Daten kein "!" gibt und die Reihenfolge von "<astate>" und "<vstate>" immer gleich ist, könnte das so gehen:
01.
@echo off & setlocal enabledelayedexpansion 
02.
set "Basis=D:\Startordner" 
03.
set "CSV=Gesamt.csv" 
04.
set "Delim=;" 
05.
 
06.
pushd "%Basis%" 
07.
del "%CSV%" 2>nul 
08.
for /f "delims=" %%i in ('dir /s /b *.nfo') do ( 
09.
    set "Record=" 
10.
    for %%f in ("<title>" "<year>" "<durance>" "<lead>" "<hidden>") do ( 
11.
        for /f "tokens=3 delims=<>" %%v in ('findstr %%f %%i') do set "Record=!Record!%Delim%%%v" 
12.
13.
    >>"%CSV%" echo !Record:~1! 
14.
15.
popd
Allerdings solltest Du keine Geschwindigkeitsrekorde erwarten ...

Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 00:48 Uhr
Hallo bastla,

danke! Das sieht schon sehr gut aus - doch haut noch nicht ganz hin, weil ich dir die Ordnerstruktur vorenthalten habe, wie ich grad merke ;)

Die Verzeichnisse und Dateinamen enthalten Leerzeichen, so dass er sie bei dem jetzigen Code nicht findet. Er sucht statt nach Datei "abcd xy (2003).nfo" jetzt nach den Dateien "abcd", "xy" und "(2003).nfo". Wahrscheinlich sucht er auch in den falschen Verzeichnissen, da diese ähnlich benannt sind. Dann würde es wunderbar hinhauen.

Dann würde mich noch interessieren, ob es möglich ist, nach dem Eintrag in den <hidden> - Tags einen weiteren folgen zu lassen, allerdings mit einem anderen Trennzeichen (Doppelpunkt und Leerzeichen?), so dass beide Einträge später dann in Excel in derselben Spalte übernommen werden. Diese Einträge befinden sich nach den <hidden> - Tags zwischen den <movement> - Tags bzw. den <size> - Tags (also Reihenfolge stimmt hier auch - kann man die an diesem auch Punkt umkehren? - das wäre wesentlich besser).

Also XML derart:

01.
(...alles wie oben...) 
02.
  <extract> 
03.
    <details> 
04.
      <astate> 
05.
        <hidden>stealth</hidden> 
06.
        <movement>move</movement> 
07.
        ... 
08.
      </astate> 
09.
      <astate> 
10.
        <hidden>stealth2</hidden> 
11.
        <movement>move2</movement> 
12.
        ... 
13.
      </astate> 
14.
      <vstate> 
15.
        <hidden>block</hidden> 
16.
        ... 
17.
        <size>large</size> 
18.
      </vstate> 
19.
    </details> 
20.
  </extract> 
21.
</data>
So dass es dann in der CSV so aussieht:

01.
Dies ist ein Titel;2006;5.3;Alfred / Josef / Mike;stealth: move;stealth2: move2;block: large
Danke nochmal und Gruß!

EDIT: Was ist, wenn Ausrufezeichen in den Daten auftauchen? Das ist in der Mehrzahl der Dateien der Fall.

EDIT 2: Leerzeichenproblem erledigt: habe einfach zwei " in diese Zeilen eingefügt:

for /f "tokens=3 delims=<>" %%v in ('findstr %%f "%%i"') do set "Record=!Record!%Delim%%%v"
Bitte warten ..
Mitglied: bastla
30.04.2010 um 01:30 Uhr
Hallo tardezyx!

Hinsichtlich der Leerzeichen in den Verzeichnis-/Dateinamen trifft mich eine Mitschuld - üblicher Weise berücksichtige ich das bereits vorsorglich (indem in Zeile 11 "%%i" unter Anführungszeichen gesetzt wird [Edit] hatte Dein EDIT 2 noch nicht gesehen [/Edit]); das hatte ich zwar in meiner ersten Version (welche mit Unterprogrammen arbeitete) auch getan - beim Versuch, die Performance zu verbessern, indem ich auf die Variante mit geschachtelten Schleifen umstellte, sind die Anführungszeichen dann leider auf der Strecke geblieben ...

... umso ärgerlicher, da ich nun (wegen der Ausrufezeichen) ohnehin wieder Unterprogramme verwenden muss.

Ohne Berücksichtigung der Zusatzanforderung hinsichtlich der "<movement>"- und "<size>"-Tags sähe das dann zunächst so aus:
01.
@echo off & setlocal 
02.
set "Basis=D:\Startordner" 
03.
set "CSV=Gesamt.csv" 
04.
set "Delim=;" 
05.
 
06.
pushd "%Basis%" 
07.
del "%CSV%" 2>nul 
08.
for /f "delims=" %%i in ('dir /s /b *.nfo') do call :ProcessFile "%%i" 
09.
popd 
10.
goto :eof 
11.
 
12.
:ProcessFile 
13.
set "Record=" 
14.
for %%f in ("<title>" "<year>" "<durance>" "<lead>" "<hidden>") do for /f "tokens=3 delims=<>" %%v in ('findstr %%f %1') do call :ProcessField "%%v" 
15.
>>"%CSV%" echo %Record:~1% 
16.
goto :eof 
17.
 
18.
:ProcessField 
19.
set "Record=%Record%%Delim%%~1" 
20.
goto :eof
Bis hierher war es einfach möglich, die einzelnen Tags in der gewünschten Reihenfolge mit "findstr" jeweils aus der übergebenen Datei heraussuchen zu lassen (und zu einer Zeile zusammenzufügen) - um die zwischen den "<hidden>"-Werten liegenden Tags zu berücksichtigen, wird es allerdings erforderlich sein, die gesamte Datei zeilenweise durchzugehen.

Da es inzwischen schon etwas spät (bzw früh ) ist, muss ich Dich in dieser Hinsicht leider auf später am Tag vertrösten ...

Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 02:03 Uhr
Hey, spitze - genau so! Danke dir wie Sau! ;)

Gut, dass du dich noch nicht weiter rangesetzt hast.

Jetzt, wo ich das so sehe, wäre es vorteilhafter, dass er das <hidden> nur aus dem <vstate> holt und danach, was in der <size> steht. Es steht aber in den XML fast immer noch was zwischen <vstate> und <hidden>.

Das sieht in der XML so aus:

01.
  ... 
02.
  <extract> 
03.
    <details> 
04.
      <astate> 
05.
        ... 
06.
      </astate> 
07.
      <astate> 
08.
        ... 
09.
      </astate> 
10.
      <vstate> 
11.
        ... 
12.
        <hidden>block</hidden> 
13.
        ... 
14.
        <size>large</size> 
15.
      </vstate> 
16.
    </details> 
17.
  </extract> 
18.
</data>
Ansonsten alles wie gehabt. Bestimmt knifflig.

Das mit den Doppelpunkten wäre erstmal egal. Falls es einfach gänge, kannst du es mir ja trotzdem noch zeigen. Vielleicht brauch ich's mal.

Guts Nächtle ;)

EDIT: Oje, jetzt hat er Probleme mit "&" im Dateiname und sagt: "Der Befehl "amp" ist entweder falsch geschrieben oder konnte nicht gefunden werden."
Bitte warten ..
Mitglied: bastla
30.04.2010 um 02:18 Uhr
Hallo tardezyx!

Wenn nur das letzte "<hidden>" benötigt wird und es "<size>" nur einmal geben sollte, könnte sich das doch jetzt noch ausgehen - versuch es mit folgendem (ungetesten) Ersatz des Teiles ab Zeile 12:
01.
:ProcessFile 
02.
set "Record=" 
03.
for %%f in ("<title>" "<year>" "<durance>" "<lead>") do for /f "tokens=3 delims=<>" %%v in ('findstr %%f %1') do call :ProcessField "%%v" 
04.
set "Hidden=" 
05.
for /f "tokens=3 delims=<>" %%v in ('findstr "<hidden>" %1') do set "Hidden=%%v" 
06.
for /f "tokens=3 delims=<>" %%v in ('findstr "<size>" %1') do set "Hidden=%Hidden%: %%v" 
07.
>>"%CSV%" echo %Record%%Hidden% 
08.
goto :eof 
09.
 
10.
:ProcessField 
11.
set "Record=%Record%%~1%Delim%" 
12.
goto :eof
Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 10:23 Uhr
Hallo bastla,

super!

Jetzt ist nur noch das Amp-Problem vorhanden, also das "&" im <title>. Falls es im Verzeichnis- und Dateinamen auftaucht, macht es keine Probleme, aber er hört sofort im <title> (dieser entspricht meist dem Dateinamen) beim "&" auf und geht zur nächsten .nfo-Datei.

Das Ergebnis sieht dann so aus:

01.
Dies ist ein Titel;2006;5.3;Alfred / Josef / Mike;block: large 
02.
Bonnie 
03.
Das ist auch ein Titel;2003;6.9;Fred / Harald;block: small
Bonnie wäre eigentlich bspw. Bonnie & Clyde.

Gruß!
Bitte warten ..
Mitglied: bastla
30.04.2010 um 10:52 Uhr
Hallo tardezyx!

Dann spendieren wir dem Batch eben noch eine Zeile 11a:
set "Record=%Record:&=^&%"
Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 11:22 Uhr
Hallo,

da kommt derselbe Fehler und er macht jetzt aus Bonnie & Clyde:

01.
Bonnie ^^
Und geht wieder auf die nächste Zeile.

Gruß!
Bitte warten ..
Mitglied: bastla
30.04.2010 um 11:32 Uhr
Hallo tardezyx!

Nur zur Sicherheit: Das gesamte Unterprogramm sieht jetzt so aus?
01.
:ProcessField 
02.
set "Record=%Record%%~1%Delim%" 
03.
set "Record=%Record:&=^&%" 
04.
goto :eof
Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 11:41 Uhr
Jap. Ich nutze Windows 7 x64 Pro.

Er sagt immer noch: "Der Befehl "amp" ist entweder falsch geschrieben oder konnte nicht gefunden werden."

Gruß!
Bitte warten ..
Mitglied: bastla
30.04.2010 um 12:43 Uhr
Hallo tardezyx!

Wenn ja ohnehin ein Import der Daten in Excel geplant ist, sollte es ja kein Problem sein, wenn die Felder unter Anführungszeichen stehen - versuch es daher mal mit dieser Variante:
01.
:ProcessField 
02.
set Record=%Record%%1%Delim% 
03.
goto :eof
Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 13:29 Uhr
Alles klar - danke dir nochmal!

Gruß!
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 17:14 Uhr
Hallo nochmal,

ich probiere gerade herum, so dass er mir während dieses Prozesses den gerade ablaufenden Titel anzeigt, den er in der Datei findet. Ich habe es hinbekommen, dass er mir die Datei anzeigt, der Titel wäre noch besser.

Ich habe da nur die 3. Zeile eingefügt:

01.
:ProcessFile 
02.
set "Record=" 
03.
for %%f in ("<title>") do echo %%i
%%i ist ja offensichtlich der Dateiname? Welche Variable ist aber der Inhalt von <title>?

Danke und Gruß!
Bitte warten ..
Mitglied: bastla
30.04.2010 um 17:23 Uhr
Hallo tardezyx!
%%i ist ja offensichtlich der Dateiname? Welche Variable ist aber der Inhalt von <title>?
Der "title", aber auch alle anderen in der Schleife ausgelesenen Felder, wird als "%%v" an das Unterprogramm ":ProcessField" übergeben und kommt dort als %1 (unter Anführungszeichen stehend) an - da der Titel das erste Feld des Datensatzes darstellt (vorher ist die entsprechende Variable "leer" bzw genauer: "not defined"), könntest Du unmittelbar nach ":ProcessField" die folgende Zeile einfügen:
if not defined Record echo %1
Grüße
bastla
Bitte warten ..
Mitglied: tardezyx
30.04.2010 um 17:39 Uhr
Danke, klappt!

Jetzt noch 'ne schöne GUI rundrum und wir sind fertig - Spässle ;)

Gruß!
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (19)

Frage von Xaero1982 zum Thema Microsoft ...

Outlook & Mail
gelöst Outlook 2010 findet ost datei nicht (19)

Frage von Floh21 zum Thema Outlook & Mail ...

Windows Server
Server 2008R2 startet nicht mehr (Bad Patch 0xa) (18)

Frage von Haures zum Thema Windows Server ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...