Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Haladok tovább az első részben megkezdett feladattal: írok egy kis konzolalkalmazást, amely
- lekérdezi az SQL Servertől a Northwind mintaadatbázis Customers táblájának rekordjait
- az egyes rekordokat XML formátumúvá alakítja az előző cikkben készített dokumentum igényeinek megfelelően
- bemásolja az XML-t a mintadokumentum másolatába, és megadott néven és helyre menti az új fájlt
Hogy izgalmasabb legyen, az Open XML mellett a LINQ (Language Integrated Query) technológiát is használom. A megoldáshoz ennélfogva a Visual Studio 2008-as verziójára van szükség.
CreateLetters.exe
Hozzunk létre egy Visual Basic konzolalkalmazást, és kereszteljük CreateLetters névre. A Main() eljárást írjuk át úgy, hogy két paramétert fogadjon (a sablonfájl elérési útja, a kész dokumentumok mappájának elérési útja), vagy írja ki a használat mikéntjét:
Sub Main(ByVal CmdArgs() As String)
If CmdArgs.Length = 2 Then
' Ide jön a levelek létrehozása
Else
Console.WriteLine( _
"Használat: CreateLetters <sablon> <célmappa>" & _
", pl. CreateLetters C:\Sablon.docx C:\Levelek")
End If
End Sub
Az ügyfelek listájának lekérdezése
A LINQ hasonlít a többi Visual Studio-beli adatelérési megoldáshoz. A különbség abban van, ahogy az adatkezelő műveletek a programkódban megjelennek. Az ügyféltábla lekérdezésének lépései:
A Server Explorerben vagy a Data / Add New Data Source... paranccsal adjuk hozzá a Northwind adatbázis Customers tábláját a projekthez.
A Solution Explorerben vagy a Project / Add New Item... paranccsal adjunk a projekthez egy LINQ to SQL Classes nevű elemet, és nevezzük el Customer-nek. A Solution Explorerben megjelenik egy Customer.dbml fájl, és megnyílik az Object Relational Designer nevű tervezőfelület.
A Server Explorerből húzzuk a Customers táblát a tervezőfelület bal oldalára, ahol létrejön egy Customer nevű osztály. A többes számból egyes számba alakítás nem véletlen, ez az osztály egy konkrét ügyfelet testesít meg. (Nem ér megkérdezni, hogy az "Ügyfelek"-ből is "Ügyfél" lesz-e.) Mentsük a projekt fájljait.
Most lekérdezhetjük az ügyfelek listáját. "Vegytiszta" SQL-t használva ezt pl. a következőképpen tehetnénk meg:
SELECT CustomerID, CompanyName, ContactName, ContactTitle FROM Customers
A LINQ-kel a fenti lekérdezést az alábbi módon írhatjuk le (a kódot a Main() eljárás If ágába, a megjegyzés helyére szúrjuk be):
Dim context As New CustomerDataContext
Dim customers = _
From c In context.Customers _
Select _
c.CustomerID, c.CompanyName, _
c.ContactName, c.ContactTitleA kapott customers gyűjtemény tartalmazza valamennyi ügyfél adatait. A levelek előállításához ennek elemein fogunk végigmenni a következő ciklusban:
For Each customer In customers
' Ide jön az egyes levelek összeállítása
Next
Az XML adatfájl összeállítása
A LINQ segítségével az XML-készítés is leegyszerűsödik, méghozzá egyetlen lépésre. Az alábbi kódot írjuk be a ciklus belsejébe:
Dim customerData As XElement = _
<CustomerData>
<CustomerID><%= customer.CustomerID %></CustomerID>
<CompanyName><%= customer.CompanyName %></CompanyName>
<ContactName><%= customer.ContactName %></ContactName>
<ContactTitle><%= customer.ContactTitle %></ContactTitle>
</CustomerData>
Feltűnő a hasonlóság az ASP.NET-tel...
Új dokumentum létrehozása a sablon alapján
A parancssorban kapott első paraméter a sablonfájl elérési útja, a második a mappáé, ahova a leveleket gyűjtjük. A kövtkező lépésben lemásoljuk a sablont, az új fájl neve az ügyfélazonosítóból származik (példa: ALFKI.docx). Az alábbi kód is a ciklus belsejébe megy:
My.Computer.FileSystem.CopyFile( _
CmdArgs(0), _
CmdArgs(1) & "\" & customer.CustomerID & ".docx", True)
A dokumentumban lévő XML adatfájl felülírása
Most jött el az ideje, hogy az Open XML csomaggal foglalkozzunk. A teendők (az eleje egy korábbi bejegyzésemből már ismerős lehet):
Töltsük le az Open XML SDK-t erről a címről, és telepítsük.
Adjunk a projekthez egy új referenciát: a .NET fülön a Microsoft.Office.DocumentFormat.OpenXML bejegyzést keressük.
A modul tetején hivatkozzuk meg ezt és a System.IO-t:
Imports _
Microsoft.Office.DocumentFormat.OpenXml.Packaging
Imports System.IOA ciklus belsejében (mostantól minden kód ide kerül) nyissuk meg az újonnan lemásolt dokumentumot mint csomagot:
Dim document As WordprocessingDocument = _
WordprocessingDocument.Open( _
CmdArgs(1) & "\" & customer.CustomerID _
& ".docx", True)Keressük meg a fő dokumentumrészt és az egyedi adatokat (az XML-t) tartalmazó részt:
Dim mainPart As MainDocumentPart = _
document.MainDocumentPart
Dim dataPart As CustomXmlPart = _
mainPart.CustomXmlParts(0)A következők kicsit bonyolultnak tűnhetnek, de ez a memóriában tárolt fájlok kezelésének jellegzetessége. Egy adatfolyam-objektumot (stream) nyitunk - ez gyakorlatilag az XML fájl. A folyam módosításához egy író objektumot (writer) használunk. Amikor ezt kiürítjük (flush), az új XML fájl bekerül a DOCX dokumentumba; mentésre nincs szükség:
Dim stream As Stream = dataPart.GetStream( _
FileMode.Create, FileAccess.ReadWrite)
Dim writer As StreamWriter = New StreamWriter(stream)
writer.Write(customerData.ToString)
writer.Flush()
Kész a fejlesztés: mentsük a projektet, majd építsük meg az alkalmazást.
Próba, szerencse
Itt az ideje, hogy megírjunk néhány levelet! Másoljuk az első részben készített dokumentumot a kívánt helyre (a C:\ is tökéletesen megfelel), és hozzunk létre egy mappát a termésnek (legyen pl. C:\Levelek). Most futtassuk az alkalmazást a következő paranccsal:
CreateLetters C:\Ügyfélértesítő.docx C:\Levelek
Ha semmit sem rontottunk el (ez fontos, hiszen a rövidség kedvéért kihagytam a hibakezelést :-)), a Levelek mappában néhány másodperc múlva 91 db Word 2007-dokumentum jelenik meg, mindegyikben a Customers tábla egy-egy rekordjának megfelelő adatok.
De a legjobb rész most jön: minden további nélkül átalakíthatjuk a sablonként szolgáló dokumentumot, a megoldás helyesen fog működni. Igazából semmit nem ronthatunk el, a tartalomvezérlők törlését ugyanis korábban megtiltottuk. Íme egy áttervezett dokumentum, ahol a mezők sorrendje és az oldal grafikai megvalósítása egyaránt új:
Vége (vagy mégsem?)
Az Open XML nemcsak a dokumentumok szövegének és grafikai elemeinek bővítését és cseréjét teszi lehetővé, hanem külső adatforrások alapján, dinamikusan történő előállításukat is. És mindezt minimális programozási igény mellett. Érdemes az új fájlformátummal és a hozzá tartozó SDK-val kísérletezni; lehet, hogy én is írok még néhány további lehetőségről itt a blogban.