Tag Archives: xml

Skrypt windows do parsowania xml umieszczonego w logu

Czasem trzeba odowiedzić loga – a tu zonk, wiadomość loggera zlepiona z xmlowym outputem:

2014-01-02 13:52:01.3850|TRACE|SuperService|Method GetStock ended with result: <Body xmlns:m="http://www.example.org/stock"><m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice></Body>

No i miliony takich linni kiedy mnie interesuje tylko ta najświeższa 🙂
Zacznijmy od pokazanej linijki – ląduje ona w pliku input.txt (jak? – o tym później) i zostanie przetworzony przez skrypt transform.bat

REM http://ss64.com/nt/for_f.html

@echo on
set file=input.txt
set out=output.xml
for /f "tokens=1,* delims=<" %%a in (%file%) do (
echo ^<DETAILS d^=^"%%a^"^>^<%%b^</DETAILS^>>%out%
)
pause

Krótki komentarz do linni
1 Tak się robi komentarze – w tym znajduje się link do fajnego omówienia tematu dzielenia tekstu w batch
3  Echo włączone – czyli widać jak nasz skrypt się wykonuje na konsoli – wystarczy zmienić parametr na off aby skrypt nie pokazywał okna
4 i 5 Ustawienie plików wejścia i wyjścia
6 Iteracja po liniach – token wydziela składniki z danej lini uzyskane za pomocą znaku rozdzielającego delims, w tym przypadku do 1 pobieram wszystko co znajduje się przed rozpoczęciem  znaku rozdzielającego – czyli aż do oraz resztę *, pierwsza wartość ląduje w zmiennej %%a  a pozostałe domyślnie w kolejnych %%b itd. do rozpoczyna sie ciało pętli
7 Do pliku output.xml zapisuję pierwszy wydobyty nie xmlowy tekst, który opakowuje  w tag – może on mieć dowolną nazwę, ja przyjąłem DETAILS oraz dodaję atrybut d który zawierać będzie wartość czyli pierwszy fragment tekstu. Wszystkie znaki specjalne które chcę zapisać do pliku escape’uje poprzez użycie daszka ^, oraz dokładam zmienną reprezentującą pierwszę linie %%a – powstaje coś takiego ^<DETAILS d^=^”%%a^”^>
Jako, że użyłem znaku < jako rozdzielacza trzeba go dodać bo jest on usuwany no i skleić z resztą lini z loga ^<%%b
Na koniec wystarczy dodać taga zamykającego ^</DETAILS^> i wszystko przekierować do pliku wynikowego >%out%
8 Zamykam petlę
9 I rozkazuję czekac skrypciochowi na moją reakcję 🙂

<DETAILS d="2014-01-02 13:52:01.3850|TRACE|SuperService|Method GetStock ended with result: "><soap:Body xmlns:m="http://www.example.org/stock"><m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice></soap:Body></DETAILS>

Jest nieźle – przy użyciu Notepad++ z zainstalowanym pluginem XML Tools wystarczy użyć opcji Pretty Print (ctrl+shift+alt+b)  i można podziwiać prawidłowo wyświetlonego XML

Ale to za mało czas na stworzenie czegoś w powershell

#last item from file
(Get-Content logfile.txt)[-2..-1]| Out-File -Encoding UTF8 input.txt
#adding xml marks to file
transform.bat
#formatting xml
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
[System.Xml.Linq.XDocument]::Load("output.xml").Save("output_pretty.xml")
Get-Content output_pretty.xml
pause

Opis linii:
1 Komentarz
2 Wyjącie ostatniej lini z pliku (Get-Content logfile.txt)[-1] więcej możecie poczytać tu: http://technet.microsoft.com/en-us/library/ee692806.aspx
Następnie trzeba zapisać ze zmienionym kodowaniem bo domyślne USC-2 Little Endian nie za bardzo podchodzi skryptowi batch 🙂
4 Mając przygotowany plik z ostatnią linią można odpalić skrypt dodający tagi
6 Korzystanie z .NETowych bibliotek – dodaje Linq
Niby to jest już nieaktualna forma ale nie ma godnego zastępnika http://stackoverflow.com/questions/12923074/how-to-load-assemblies-in-powershell
7 Tu następuje proces transformacji jednolinijkowego xml do pliku
8 Zawartość ląduje na konsoli 

TADAAA – to już jest czytelne
powershell

Oczywiście przedstawiony case jest dość specyficzny – ale stanowi świetną bazę dla dalszych transformacji i eksperymentów.