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 word\document.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)



Balássy György (MS RD, ASP.NET MVP, MCTS)

Balássy György (MS RD, ASP.NET MVP, MCTS) Villamosmérnök, a BME Automatizálási és Alkalmazott Informatikai Tanszékén webportálok fejlesztését oktatja. 2000 óta foglalkozik a Microsoft .NET platformjával, melynek meghonosításában jelentős szerepet vállalt előadóként, konzulensként és A .NET Framework és programozása című könyv társszerzőjeként. Az MSDN Kompetencia Központon belül a Portál Technológiák Csoport vezetője, szakterülete web alapú rendszerek fejlesztése és üzemeltetése. 2004-ben Magyarországon elsőként kapta meg a Most Valuable Professional címet, majd 2005 óta a Microsoft magyarországi regionális igazgatója. Publikációi a Technet Magazinban, az MSDN Kompetencia Központ honlapján és szakmai blogjában olvashatóak.

2008.04.09. 9:20:43 | Permalink | Hozzászólások: 0 | Tárgyszavak: , ,


  • Word dokumentum generálása adatkötéssel - 3. rész: Kontroll

    Balássy György (MS RD, ASP.NET MVP, MCTS) Bár a Word 2007 preferált fájlformátuma a DOCX teljes mértékben nyitott és XML alapú, elmondhatjuk, hogy a tartalom programozott közvetlen előállítása mégsem igazán egyszerű, mert az adat és a megjelenítés erősen keveredik a WordML nyelvben. Már a Word 2003-ban megjelent az a lehetőség, hogy a dokumentumhoz XSD sémát rendelhetünk, amely alapján a szöveg egyes részeit nyers XML-ben exportálhatjuk, de sajnos ez nem teszi lehetővé a tartalom generálását, ahogyan azt korábban láttuk. Tovább »
  • Olaszország 2007

    Dávid Zoltán Velence, Verona, Garda tó, Tenno, Arco, túrázás, kemping. Tovább »


Írja meg Ön is véleményét!


Hozzászólásokat csak regisztrált, bejelentkezett felhasználóktól tudunk elfogadni!

Hozzászólások