Word dokumentum generálása adatkötéssel – 1. rész: A fáraó átka

Gyakori feladat, hogy valamely alkalmazásunkból Office dokumentumot kell előállítanunk. Mivel az Office 2007 alapértelmezett fájl formátuma, az Office Open XML éppen ebben a hónapban kapta meg a szükséges szavazatokat, hogy az ECMA (ECMA 376, 2006. december) után ISO szabvánnyá is válhasson, aktuális a téma!

Az egyszerűség kedvéért koncentráljunk a Wordre. Talán már köztudott, hogy az új DOCX fájl valójában egy ZIP állomány, benne sok apró fájllal, melynek többsége XML. Ki is próbálhatjuk, készítsünk például egy igen egyszerű dokumentumot:

Példa dokumentum

Mentsük el a dokumentumot mondjuk Szia.docx néven, majd nevezzük át Szia.docx.zip-re és akár a Windows segítségével csomagoljuk ki. Elég sok fájlt fogunk találni benne, hogy a lényegre térjek, a dokumentum szövege a worddocument.xml fájlban található:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                            xmlns:o="urn:schemas-microsoft-com:office:office" 
                            xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" 
                            xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" 
                            xmlns:v="urn:schemas-microsoft-com:vml" 
                            xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" 
                            xmlns:w10="urn:schemas-microsoft-com:office:word" 
                            xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
                            xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
        <w:body>
            <w:p w:rsidR="00A268F4" w:rsidRDefault="00632D74">
                <w:r>
                    <w:t xml:space="preserve">Szia Word 2007! </w:t>
                </w:r>
            </w:p>
            <w:sectPr w:rsidR="00A268F4" w:rsidSect="00E20B73">
                <w:pgSz w:w="11906" w:h="16838"/>
                <w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/>
                <w:cols w:space="708"/>
                <w:docGrid w:linePitch="360"/>
            </w:sectPr>
        </w:body>
    </w:document>

A lényeg ott van középen, az xml:space=preserve attribútumnak köszönhetően még az utolsó szóköz is megmaradt.

A .NET Framework 3.0 verziójától kezdve van lehetőségünk arra, hogy ezt a tömörített fájlt, az ún. package-et programozottan kezeljük a System.IO.Packaging névtérben lévő Packaging API segítségével. Az API támogatása addig terjed, hogy meg tudja nyitni a package-et és segít elérni benne az egyes részeket, az ún. package part-okat. A part-ok tartalmát streamek formájában tudjuk elérni és mivel többségük formátuma XML, ezért a System.Xml névtérben található jól ismert osztályokkal gyerekjáték (?) a tartalom módosítása.

Ezek ismeretében hogyan foghatunk hozzá egy Word dokumentum előállításához? Több lehetőség is van:

  1. Az API segítségével létrehozunk egy új package-et, majd abban új part-okat, és elkezdjük írni az XML-t. Mivel ebben az esetben tiszta lappal indulunk, ismernünk kell a Word ML nyelvet, amely értelmet ad a fenti XML-nek is. Ez nehezen járható út, de egyszerűbb esetekben működhet.
  2. Másik lehetőség, hogy Worddel létrehozunk egy ízlésünknek megfelelő dokumentumot és abban megjelöljük azokat a részeket, amiket cserélni szeretnénk. Ez már egyszerűbb, mert nem kell az egész dokumentumot megírnunk, csak a változó részeket kell megkeresnünk és átírnunk. Sajnos azonban ez sem triviális, mindjárt meglátjuk, miért…

Vegyük például a fenti dokumentumot és ne változtassuk meg a tartalmát, csak futtassunk egy helyesírás ellenőrzést, mégpedig angol nyelven. Szegény Word nem fogja megérteni a Szia szót, ráadásul és ezt a Word ML-ben is megjeleníti, nálam például ez lett az új document.xml (a sémákat kihagyva):

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document ...>
        <w:body>
            <w:p w:rsidR="00A268F4" w:rsidRPr="00144B7E" w:rsidRDefault="00632D74">
                <w:pPr>
                    <w:rPr>
                        <w:lang w:val="en-US"/>
                    </w:rPr>
                </w:pPr>
                <w:proofErr w:type="spellStart"/>
                <w:r w:rsidRPr="00144B7E">
                    <w:rPr>
                        <w:lang w:val="en-US"/>
                    </w:rPr>
                    <w:t>Szia</w:t>
                </w:r>
                <w:proofErr w:type="spellEnd"/>
                <w:r w:rsidRPr="00144B7E">
                    <w:rPr>
                        <w:lang w:val="en-US"/>
                    </w:rPr>
                    <w:t xml:space="preserve"> Word 2007! </w:t>
                </w:r>
            </w:p>
            <w:sectPr w:rsidR="00A268F4" w:rsidRPr="00144B7E" w:rsidSect="00E20B73">
                <w:pgSz w:w="11906" w:h="16838"/>
                <w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/>
                <w:cols w:space="708"/>
                <w:docGrid w:linePitch="360"/>
            </w:sectPr>
        </w:body>
    </w:document>

Bár nem változtattuk meg a dokumentum tartalmát, a belső szerkezete mégis megváltozott. Ahhoz, hogy ezt megértsük, kicsit dekódolnunk kell a fenti tag-eket:

  • A w:p egy paragraph, azaz egy bekezdés leírása.
  • A bekezdés tulajdonságai, jelen esetben, hogy angol nyelvű, a w:pPr elemben, paragraph properties elemben találhatóak.
  • A bekezdésen belül ún. run elem található, erre vonatkozik a w:r. A run tulajdonságait a run properties elem, a w:rPr tartalmazza.
  • A szöveg a run elemen belül text elemekben található, ez a w:t.

Ezek közül a legfontosabb a run. A run ugyanis a legkisebb formázható egység a Wordben. Másként fogalmazva: nem szövegre alkalmazzuk a formázásokat, hanem vagy bekezdésre, vagy run-ra. Tehát ha van egy összefüggő szövegünk, majd azt elkezdjük formázgatni, run-okra fog szétesni. Nézzünk erre is egy példát előbb Wordben:

Szia - tarkán

Majd lássuk ugyanezt a bekezdést Word ML-ben is:

    <w:p w:rsidR="00A268F4" w:rsidRDefault="00DF7BD5">
        <w:r>
            <w:t>S</w:t>
        </w:r>
        <w:r w:rsidRPr="00DF7BD5">
            <w:rPr>
                <w:b/>
            </w:rPr>
            <w:t>z</w:t>
        </w:r>
        <w:r w:rsidRPr="00DF7BD5">
            <w:rPr>
                <w:color w:val="FF0000"/>
            </w:rPr>
            <w:t>i</w:t>
        </w:r>
        <w:r w:rsidRPr="00DF7BD5">
            <w:rPr>
                <w:i/>
            </w:rPr>
            <w:t>a</w:t>
        </w:r>
    </w:p>

Egy kis segítség a megértéshez: a w:color talán nyilvánvaló, a hozzá tartozó FF0000 érték webfejlesztőknek különösen ismerős lehet, ez RGB-ben a piros. A w:b bold-ot, azaz félkövér formázást, a w:i pedig italic, azaz dőlt betűs formázást jelent.

Miért van szükség arra, hogy a run-on belül még újabb w:t text elemek is legyenek? Azért, mert ott nem csak szöveg lehet, lehetnek láthatatlan karakerek is. Íme két szöveg, közöttük pedig egy sortörés (nem új bekezdés!):

Sortöréssel

A sortörés egy speciális w:br tagként jelenik meg Word ML-ben:

    <w:p w:rsidR="00A268F4" w:rsidRDefault="003A21DF">
        <w:r>
            <w:t>Szia</w:t>
        </w:r>
        <w:r>
            <w:br/>
            <w:t>Word!</w:t>
        </w:r>
    </w:p>

Ráadásul teljesen jogos egy szöveget több run-ra bontani akkor is, ha azok semmiben nem különböznek egymástól. Sőt, nem csak formázáskor, hanem egyéb tulajdonságok változásakor is több run-ra tagolódik a szöveg, ahogy ezt az első példában a helyesírás ellenőrzésnél láttuk. Megváltozott az XML szerkezete, pedig mi nem is változtattunk a szövegen, de a Word igen!

Összefoglalva: bár a Word dokumentum belső formátuma XML, aminek a feldolgozásához kapunk API-t, a feladatnak az a része, hogy megtaláljuk a felülírandó szöveget az XML-ben nem egyszerű, mert az XML szerkezete változhat. Ezek alapján elmondhatjuk, hogy a kettes számmal jelölt megoldási módszerünk is nehezen megvalósíthatónak bizonyult.

Szerencsére van ennél is jobb megoldás, mégpedig…

(folytatjuk)

 

3 thoughts on “Word dokumentum generálása adatkötéssel – 1. rész: A fáraó átka

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s