XML

XMLStarlet



XML Starlet parancssori alkalmazás

Az XMLStarlet programmal nagyon sok XML-lel kapcsolatos feladatot hajthatunk végre kényelmes, parancssorról vezérelhető felületen.Nagyszerűen használható a példák minél egyszerűbb környezetben való kipróbálására, hiszen sokszor a befoglaló program (praktikusan Java program) megírása bonyolult lenne.  A program írója, Mikhail Grushinskiy a programot a szabad szoftverek esetében megszokott MIT licensz alatt tette elérhetővé.Ez azt jelenti, hogy saját termékeinkbe is beépíthetjük.

A program rendelkezik a szokásos információs opciókkal:

xmlstarlet --version             -- verzió információ megjelenítése

xmlstarlet –-help                -- segítő képernyő megmutatása

 

A lényegi funkcionalitást különböző alparancsok alatt valósították meg:

xmlstarlet ed      -- XML fájlok módosítása

xmlstarlet sel     -- XPath kifejezések értelmezése XML dokumentumon

xmlstarlet tr      -- XSLT traanszformáció végrehajtása XML dokumentumon

xmlstarlet val     -- XML dokumentum validálása, esetleg DTD, XSD vagy RelaxNG segítségével

xmlstarlet fo      -- XML dokumentumok formázása

xmlstarlet el      -- XML dokumentum struktúrájának megmutatása, mintha könyvtárstruktúra lenne

xmlstarlet c14n    -- XML kanonizálás

xmlstarlet ls      -- a UNIX ls parancsának XML kimenettel rendelkező verziója

xmlstarlet esc     -- XML-ben kivételesen kezelt karakterek stringbeli eszképelése

xmlstarlet unesc   -- az esc inverze

Mindegyik parancsról lekérdezhető az aktuális dokumentációja az xmlstarlet <parancs> --help kiadásával.

Kiválasztás/lekérdezés XML dokumentumból

Erre a feladatra a select parancs való, ami sel-ként is rövidíthető, lényegében egy XSLT-t állítunk össze parancssori kapcsolókkal, amit aztán le is futtatunk XML fileokra.

Forma:

 xmlstarlet select <globális kapcsolók> {<template>} [ <xml-file> … ]

A globális opciók közül a fontosabbak:

     -C     -- a generált XSLT kiírása

     -T     -- a kimenet szöveg (xml helyett)

     -I     -- a kimenet legyen indentált

     -D     -- ne hagyjuk el az XML deklarációt

     -B     -- nem szignifikáns szóközök elhagyása a kimenetből

     --net  -- DTD-k és entitások letöltése szükség esetén az internetről

Template definiálása: -t <opciók>, ahol a lehetséges opciók a template leírásához:

     -c <xpath>    -- XPath kifejezés által meghatározott rész másolása

     -v <xpath>    -- XPath kifejezés kiértékelése

     -o <string>   -- string kiírása a kimenetben

     -n            -- egy újsor kiírása a kimenetben

     -m <xpath>    -- XPath kifejezés illesztése (for-each)

     -i <t-xpath>  -- tesztelő XPath kifejezéssel if generálása (<xsl:if test=”t-xpath”>)

     -e <name>     -- adott nevű elem létrehozása (<xsl:element name=”name”>)

     -a <name>     -- attribútum létrehozása (<xs:attribute name=”name”>)

     -b            -- előző szint lezárása (pl. elem, attribútum)

     -s X:Y:Z xp   -- csak –m után használva xp kifejezés szerinti X:Y:Z módú rendezés:

         ha X az az A – növekvő sorrend

         ha X az a  D – csökkenő sorrend

         ha Y az az N – szám szerinti rendezés

         ha Y az a  T – szöveg szerinti rendezés

         ha Z az az U – nagybetűsek előre

         ha Z az az L – kisbetűsek előre

Nézzünk egy példát!

Tegyük fel, hogy az alábbi parancssort futtatjuk le:

 xml sel -t -c "xpath0" -m "xpath1" -m "xpath2" -v "xpath3" \

        -t -m "xpath4" -c "xpath5"

Ez pontosan ekvivalens azzal, mintha az alábbi módon megírt XSLT-t alkalmaznánk:

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

  <xsl:call-template name="t1"/>

  <xsl:call-template name="t2"/>

</xsl:template>

<xsl:template name="t1">

  <xsl:copy-of select="xpath0"/>

  <xsl:for-each select="xpath1">

    <xsl:for-each select="xpath2">

      <xsl:value-of select="xpath3"/>

    </xsl:for-each>

  </xsl:for-each>

</xsl:template>

<xsl:template name="t2">

  <xsl:for-each select="xpath4">

    <xsl:copy-of select="xpath5"/>

  </xsl:for-each>

</xsl:template>

</xsl:stylesheet>

Érdemes megjegyezni, hogy a XMLStarlet a libxslt nevű programfüggvény-gyűjteményt használja, így annak dokumentációja pár specialitást illetően szintén irányadó lehet.

XML dokumentum módosítása

Erre a feladatra az edit parancs való, ami ed-ként is rövidíthető.

Forma: xmlstarlet edit <globális kapcsolók> {<akció>} [ <xml-file> … ]

            

A globális opciók közül a fontosabbak:

     -P     -- eredeti formázás megtartása

     -S     -- nem szignifikáns szóközök elhelyezkedésének megtartása

     -I     -- XML deklaráció elhagyása

     -O     -- ne hagyjuk el az XML deklarációt

Akció definiálása:

     -d <xpath>    -- XPath kifejezés által meghatározott rész törlése

     -i <xpath> -t elem|text|attr –n <név> -v <érték>

-- XPath kifejezés elé a megfelelő típussal, névvel és értékkel rendelkező  csúcs beszúrása

     -a <xpath> -t elem|text|attr –n <név> -v <érték>

-- XPath kifejezés után a megfelelő típussal, névvel és értékkel rendelkező  csúcs beszúrása

     -s <xpath> -t elem|text|attr –n <név> -v <érték>

-- XPath kifejezés által meghatározott csúcs belsejébe beszúrás a megfelelő típussal, névvel és értékkel az eddigi gyerekek után

     -m <x1> <x2>  -- a UNIX mv parancsa XML-re, x1 XPath által meghatározott rész x2-be mozgatása

     -r <x1> -v n  -- x1 által meghatározott XPath kifejezés csúcsának új neve n lesz

     -u <x1> -v n  -- x1 által meghatározott XPath kifejezés csúcsának új értéke n lesz

Tekintsük az alábbi nagyon egyszerű XML dokumentumot, amit aztán a most bemutatott parancsokkal fogunk bővíteni/szűkíteni/átalakítani.

<?xml version=”1.0”?>

<test>

     <first/>

     <second/>

</test>

 

Csúcs törlése:

% xmlstarlet ed –d //test/first test.xml

<?xml version=”1.0”?>

<test>

     <second/>

</test>

Csúcs beszúrása meglévő csúcs elé:

% xmlstarlet ed –i //test/second –t elem –n insert –v now test.xml

<?xml version=”1.0”?>

<test>

     <first/>

     <insert>now</insert>

     <second/>

</test>

Csúcs beszúrása meglévő csúcs mögé:

% xmlstarlet ed –a //test/second –t elem –n insert –v now test.xml

<?xml version=”1.0”?>

<test>

     <first/>

     <second/>

     <insert>now</insert>

</test>

Csúcs létrehozása meglévő csúcs új leszármazottjaként:

% xmlstarlet ed –s //test/second –t elem –n insert –v now test.xml

<?xml version=”1.0”?>

<test>

     <first/>

     <second>

         <subnode>now</subnode>

     </second>

</test>

Részfa mozgatása/áthelyezése:

% xmlstarlet ed –m //test/first //test/second test.xml

<?xml version=”1.0”?>

<test>

     <second>

         <first/>

     </second>

</test>

Csúcs átnevezése:

% xmlstarlet ed –r //test/first –v new-name test.xml

<?xml version=”1.0”?>

<test>

     <new-name/>

     <second/>

</test>

Csúcs értékének módosítása:

% xmlstarlet ed –u //test/first –v new-value test.xml

<?xml version=”1.0”?>

<test>

     <first>new-value</first>

     <second/>

</test>

Egyszerre több akciót is véghezvihetünk, pl.:

% xmlstarlet ed –s //test/second –t elem –n subnode –v now –m //test/second/subnode //test –r //test/subnode –v insert test.xml

<?xml version=”1.0”?>

<test>

     <first/>

     <second/>

     <insert>now</insert>

</test>

A UNIX ls parancsa XML kimenettel

Lehetőség van az aktuális könyvtár XML-ként való listázására az xmlstarlet ls paranccsal.  Ez többek közt kitűnő tesztadatok biztosításához, mikor az XML-ről tanulunk.  Lássunk egy példakimenetet az otthoni számítógépünk /tmp alkönyvtárán:

<dir>

<d p="rwxrwxrwt" a="20060112T170548Z" m="20060112T170336Z" s="4096"             n=".X11-unix"/>

<d p="rwxrwxrwt" a="20060112T170548Z" m="20060112T170405Z" s="4096"             n=".ICE-unix"/>

<d p="rwx------" a="20060112T170353Z" m="20060112T214414Z" s="4096"             n="kde-risko"/>

<f p="r--r--r--" a="20060112T170553Z" m="20060112T170553Z" s="11"               n=".X0-lock"/>

<d p="rwx------" a="20060112T170350Z" m="20060112T170350Z" s="4096"             n="ssh-EZsmXc1230"/>

<d p="rwx------" a="20060112T170350Z" m="20060112T170350Z" s="4096"             n="ssh-szQdIQ1230"/>

<d p="rwx------" a="20060112T170353Z" m="20060112T214414Z" s="4096"             n="ksocket-risko"/>

<d p="rwx------" a="20060112T170406Z" m="20060112T170407Z" s="4096"             n="mcop-risko"/>

<d p="rwx------" a="19700101T000000Z" m="20060112T190225Z" s="4096"             n="orbit-risko"/>

<d p="rwx------" a="20060112T170445Z" m="20060112T190225Z" s="4096"             n="gconfd-risko"/>

<f p="rw-r--r--" a="20060112T190330Z" m="20050131T053735Z" s="1184"             n="ziyi_key_2005.asc"/>

<d p="rwxr-xr-x" a="20060112T195041Z" m="20060112T195200Z" s="4096"             n="timicd"/>

<s p="rwxr-xr-x" a="20060112T221912Z" m="20060112T194836Z" s="0"                n="xmms_risko.0"/>

<f p="rw-------" a="20060112T202405Z" m="20060112T202409Z" s="50814"            n="tetex.postinst.XXQlIOuk"/>

<f p="rw-r--r--" a="20060112T220343Z" m="20060112T215243Z" s="58"               n="test.xml"/>

</dir>

Természetesen egy ilyen kimenet az ember számára nehezen olvasható, azonban nagyon könnyen átalakíthatjuk XSLT-vel valami olvasható formátumra.  Gondoljuk meg, hogy egyszerű UNIX pipe-okkal beadhatjuk ezt a kimentet egy következő, xmlstarlet sel parancsnak.

Legyen a feladat az, hogy emuláljuk a UNIX ls -1 kimenetét, de azzal a módosítással, hogy a könyvtárnevek végére egy ’/’ jelet teszünk, így a tömör kimenetben is könnyedén látszik, ha valami könyvtár.  A megoldó parancs:

xmlstarlet ls | xmlstarlet sel –T –t –m ‘//dir/*[not(self::d)]’ –v ‘@n’ –n –t –m ‘//dir/d’ –v ‘@n’ –o ‘/’ –n

Az első templateben kizártuk az XPath kifejezéssel a könyvtárakat és ezért csak a név attribútumot, majd egy új sort írattunk ki.  A második template-ben azonban csak a könyvtárakat járjuk be és mindegyik könyvtárnév után, de még az új sor előtt egy / jelet is kiírunk a kimenetben.  A –T opcióval jeleztük, hogy szöveges kimenetet kérünk, nem XML-t.

Stringek eszképelése XML kompatibilis módon és visszaalakítás

XML dokumentumokban a <, >, & karakterek a jelölésrendszer részét képezik, így nem tudjuk például azt az egyenlőtlenséget leírni, hogy 2<3.          

Ehelyett már a HTML-ből megszokott módon a következőt kell írnunk: 2&lt;3, a > jelet az &gt;, az & jelet az &amp; helyettesíti.

Az XMLStarlet programcsomag tartalmaz egy parancsot ezen konverzió és az inverzének elvégzésére is, lássuk:

risko@bubble:/tmp$ xmlstarlet esc '2<3 && 5>6'

2&lt;3 &amp;&amp; 5&gt;6

risko@bubble:/tmp$ xmlstarlet esc '2<3 && 5>6' | xmlstarlet unesc

2<3 && 5>6