TreeView a převod databázových tabulek do XML

V dnešním dílu se zaměříme na komponentu umožňující zobrazení stromových hierarchických dat. Jedná se o TreeView představený v minulém dílu. Pomocí SQLXML si ukážeme , jak se dají data z tabulek v databázi jednoduše převést do XML.

TreeView jsme si představili v předchozím dílu tohoto seriálu o .NET. Jedná se o komponentu umožňující zobrazení stromových dat. Osobně považuji stromové hierarchie za velice častý a důležitý způsob ukládání dat. Setkáme se sním v každém intranetu, work-flow manageru, adresářových strukturách a pod.

Představte si například stromovou strukturu zaměstnanců v systému, který má za úkol sledovat work-flow dokumentů od podřízených zaměstnanců jejich nadřízeným. Ukázka takového stromu může vypadat:

Problém s implementací stromové struktury je, jak data efektivně uložit. Jako ideální pro práci se stromovou strukturou se jeví XML – umožňuje libovolný počet vnoření a data jsou uložena skutečně tak, aby jejich pozice odpovídala pozici ve stromu. TreeView komponenta také pracuje nativně se XML jako se zdrojem dat.

Ukládat ale data do souboru je značně neefektivní v případě vysoké zátěže stránek ASP.NET. Na tyto účely je nutné nasadit databázi jako například SQL Server. V takovém případě tedy máme dvě výchozí podmínky:

  1. Uložit celou strukturu do tabulek databázi (lineární seznam)
  2. Přeložit tyto informace při výstupu do stromové struktury XML pro zobrazení komponentou TreeView.

1. Ukládání stromové struktury do databáze

Podívejme se nejdříve na první problém. Typické řešení takové struktury by byla následující tabulka:

Políčko ParentID obsahuje ID nadřazeného záznamu. V Employee pak bude obsaženo jméno samotného zaměstnance. Zaměstnanci na kořenové úrovni – ti co nemají žádné nadřízené – budou mít ParentID = 0. Pokud bychom chtěli vybrat všechny podřízené lidi zaměstnanci s daným ID, vypadal by SQL dotaz takto:

SELECT * FROM Tree WHERE ParentID = 0

ID ParentID Employee
1 0 Bill Gates
2 0 Jiří Hlavenka

Microsoft SQL Server 2000 umožňuje vrácení výsledů dotazů v podobě XML. Pokud obměníme uvedený dotaz připojení klíčových slov FOR XML nakonec dotazu dostaneme tento výsledek:

SELECT * FROM Tree WHERE ParentID = 0 FOR XML

<Tree ID="1" ParentID="0" Employee="Bill Gates"/>
<Tree ID="2" ParentID="0" Employee="Jiří Hlavenka"/>

Problémem je, že takový dotaz vrátí vždy pouze jednu úroveň – nedokáže vrátit celý strom. Ten se musí z jednotlivých dotazů poskládat.

2. TreeView a SQLXML

Komponenta TreeView nám umožňuje velice jednoduše zobrazovat stromová data. V předchozím dílu jsme si ukázali, jak staticky nadefinovat data pro TreeView. V dnešním příkladu nám toto stačit nebude – data se můžou v databázi měnit.

TreeView naštěstí obsahuje vlastnost, která umožňuje získat data z externího zdroje dynamicky:

TreeView.TreeNodeSrc = “strom.xml”;

Umožní zobrazit data ze souboru strom.xml. XML data v takovém souboru musí být formátována pro použití v TreeView. Zde je ukázka výpisu zdrojového souboru stromu ze začátku článku:

<?xml version="1.0" encoding="utf-8"?>
<TREENODES>
<treenode Text="Bill Gates">
<treenode Text="Peter Newman"/>
</treenode>

<treenode Text="Jiří Hlavenka">

<treenode Text="Marek Němec">
<treenode Text="Tomáš Tichý"/>
<treenode Text="Bill Clinton"/>
</treenode>

<treenode Text="Pepa Nový"/>
</treenode>
</TREENODES>

Jak tedy vygenerujeme takový XML soubor z databázové tabulky navržené v bodě 1? Pochopitelně bychom mohli vytvářet strom programově tím, že bychom rekurzivně spojili výsledy všech dotazů. Mám pro vás ale elegantnější řešení. Jmenuje se SQLXML. Tento nástroj slouží jako nadstavba SQL Serveru 2000. Umožňuje rozšíření IIS o funkce zpřístupňující databázi pomocí XML a HTTP. Abychom nezůstali u suché definice, ukážu příklad. Po správném nastavení SQLXML stačí do internetového prohlížeče zadat URL virtuálního adresáře a SQL server nám vrátí výsledek dotazu:

Jak tedy nastavíme SQLXML aby nám umožnilo zobrazování výsledků dotazů ? Následujte tyto kroky:

  1. Nejdříve vytvoříme soubor s definicí SQL dotazu (template), který chceme zpřístupnit pomocí URL a uložíme jej jako TreeSQLXML.xml:

    <ROOT xmlns:sql="urn:schemas-microsoft-com:xml-sql" sql:xsl="TreeSQLXML.xslt">
    <sql:header>
    <sql:param name=`ParentID`>0</sql:param>
    </sql:header>
    <sql:query>
    SELECT * FROM Tree WHERE ParentID = @ParentID FOR XML AUTO
    </sql:query>
    </ROOT>

    V sekci sql:header je definován parametr ParentID, kterým budeme moci v URL specifikovat, čí zaměstnance (podřízené) chceme vyhledat. V sekci sql:query následuje samotný dotaz následovaný klauzulí FOR XML AUTO, která způsobuje formátování výsledku do XML.

  2. Poté nastavíme virtuální adresář IIS pomocí utility Configure IIS Support, která je součástí SQLXML balíčku:

    V záložce Security musíme nastavit přihlašovací účet k SQL serveru. V záložce Virtual Names definujeme virtuální jméno pro službu. Typ zvolíme template a do položky Path zadáme adresář v němž sídlí vytvořený template soubor TreeSQLXML.xml. URL pro vyvolání dotazu sídlícího v tomto souboru je

    http://<jméno servru>/<virtuální adresář>/<virtuální jméno>/TreeSQLXML.xml

  3. Jako poslední krok musíme vytvořit soubor pro XSLT transformaci na tvar vhodný pro použití s komponentou TreeView. Pokud totiž porovnáte XML generované XMLSQL a XML, které jsem uvedl jako ukázkový zdroj dat pro TreeView, zjistíte, že struktura je sice stejná, jsou ale použité rozdílné názvy XML značek. Tento XSLT soubor provede žádanou přeměnu (uložme jej jako TreeSQLXML.xslt do stejného adresáře):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template match="ROOT">
<TREENODES>
<xsl:apply-templates/>
</TREENODES>
</xsl:template>

<xsl:template match="Tree">
<treenode>
<xsl:attribute name="Text"><xsl:value-of select="@Employee"/></xsl:attribute>
<xsl:attribute name="TreeNodeSrc">http://localhost/sqlxml/templates/TreeSQLXML.xml?ParentID=<xsl:value-of select="@ID"/></xsl:attribute>
</treenode>
</xsl:template>
</xsl:stylesheet>

Pokud nyní zavoláme URL (v mém případě je to http://localhost/sqlxml/templates/TreeSQLXML.xml?ParentID=0) pro službu můžeme vidět následující XML vrácené z dotazu:

<?xml version="1.0" encoding="utf-8"?>
<TREENODES xmlns:fo="http://www.w3.org/1999/XSL/Format">
<treenode Text="Bill Gates" TreeNodeSrc="http://localhost/sqlxml/templates/TreeSQLXML.xml?ParentID=1" />
<treenode Text="Jiří Hlavenka" TreeNodeSrc="http://localhost/sqlxml/templates/TreeSQLXML.xml?ParentID=2" />
</TREENODES>

Každá z větví obsahuje odkaz na XML dceřiné části stromku pomocí vlastnosti TreeNodeSrc. Data jsou tedy připravena na použití v komponentě TreeView. Vytvořme proto pokusný formulář, který bude obsahovat tuto komponentu, nastavme její vlastnost TreeNodeSrc v okně properties na hodnotu http://localhost/sqlxml/templates/TreeSQLXML.xml . Po spuštění programu můžeme vidět stromek, který je dynamicky generován z databáze:

Můžete si všimnout, že jednotlivé větve jsou načítány jenom pokud jsou potřeba – jenom v případě rozbalení. Tento přístup šetří přenosové pásmo a snižuje zátěž na databázi:

Závěr

Použití TreeView za pomocí XML dat generovaných SQLXML je skutečně velice účinné a jednoduché. SQLXML je šikovný nástroj a jeho použití není omezeno pouze na generování dat pro TreeView. Je pomocí něj například možné vytvářet webové služby, které budou nabízet data z SQL serveru pomocí protokolu SOAP. Ale o tom až někdy jindy.

Diskuze (6) Další článek: Trvá vám dlouho otevření souboru ve Windows XP po síti?

Témata článku: , , , , , , , , , , , , , , , , , , , ,