XmlDataDocument a zobrazení stromové struktury přes XSLT v ASP.NET
Stromovou strukturu dat uložených v SQL databázi lze zobrazit mnoha způsoby. V tomto článku si ukážeme postup využívající technologii XSLT a výsledkem naší práce bude zobrazení strukturovaného diskusního fóra. Analýza relací mezi příspěvky nebude úkol pro C# kód, ale bude plně v moci XSL transformace.
Prolog
K tomuto článku mě inspiroval Pavel Růžička svým článkem SqlDataAdapter a zobrazení stromové struktury Repeaterem v ASP.NET, ve kterém řešil podobné zadání poměrně sofistikovaným způsobem. Já bych vám chtěl nabídnout o něco jednodušší řešení s XSL transformací v hlavní roli. Základním problémem zadání je změna uspořádání jednotlivých příspěvků v diskusi z dvojrozměrné databázové tabulky do přehledné stromové struktury, kterou pak zobrazíme na své webové stránce – jde vlastně o transformaci dat, a to je ta správná úloha pro XSLT.
Aplikace se nejdříve musí postarat o přečtení vstupních dat a ty pak musí předat transformaci. Třídu SqlDataAdapter
již znáte, dnes se seznámíme s třídou XmlDataDocument
, kterou použijeme pro převod dat z DataSetu na XmlDocument
, který pak putuje do transformace, jejíž výsledek bude již toužebně očekávaný HTML kód. Avšak nepředbíhejme a začněme pěkně od začátku.
Zdrojová data
Mějme databázi obsahující tabulku diskuse. Tato tabulka obsahuje jednotlivé diskusní příspěvky uspořádané do stromové struktury takovým způsobem, že každý příspěvek odkazuje na svůj nadřazený jeho identifikátorem. Vzniká tak vztah potomek – rodič. Naše tabulka má tyto sloupce…
Sloupec | Datový typ | Popis |
---|---|---|
ID | int | Unikátní identifikátor příspěvku, primární klíč. |
pID | int | ID nadřazeného příspěvku nebo NULL u kořenového příspěvku. |
autor | varchar | Nick autora příspěvku. |
varchar | Email autora příspěvku. | |
obsah | varchar | Text příspěvku. |
…a může obsahovat například následující data:
ID | pID | autor | obsah | |
---|---|---|---|---|
1 | NULL | paya | NULL | 4all: Ahoj, jdeme na pivo? |
2 | 1 | pierre | ja@pierre.cz | OK, v 19h na Stodolní? |
3 | 2 | paya | NULL | Domluveno :) |
4 | NULL | … | NULL | Nekuřte, škodí to zdraví… :-) |
5 | 1 | zila | NULL | Asi ne, jsem nějaký unavený… |
Jak vidíte, příspěvky jsou trochu zpřeházené, některá pole nejsou vyplněná, a v kořenu diskuse je více než jeden příspěvek. Nic z toho ale nepředstavuje podstatný problém, jak uvidíte později.
Vytvoření projektu
Náš úkol je velice jednoduchý. Jeho základem bude jediná stránka, kterou si pojmenujeme diskuse.aspx a bude obsahovat následující kód:
<%@ Page language=“c#“ Codebehind=“Diskuse.aspx.cs“ AutoEventWireup=“false“ Inherits=“Interval.CZ.Diskuse.Diskuse“ %>
<html>
<body MS_POSITIONING=“GridLayout“>
<asp:Xml
id=“Tree“
TransformSource=“diskuse.xsl“
runat=“server“>
</asp:Xml>
</body>
</html>
Jak vidíte, samotnou transformaci budeme provádět standardním XML webcontrolem. Potřebný stylesheet si napíšeme později, vstupní dokument bude dodán v metodě Page_Load
stránky. Přejdeme tedy ke kódu stránky a nejdříve deklarujeme potřebné jmenné prostory. Budeme pracovat s konfigurací aplikace, s daty, s připojením k MS SQL serveru a s XML.
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
Načtení vstupních dat
Prvním úkolem stránky bude samozřejmě získání dat z databáze a převod do XML formátu, aby mohly putovat dále do transformace. Mohli bychom sice pro přístup k datům použít komponentu SQLXML, to by však znamenalo závislost na její existenci a já vám chci ukázat způsob, který je trochu bližší standardním metodám přístupu k datům.
Aplikace potřebuje znát připojovací řetězec (connection string) k databázi a dotaz vracející požadovaná data. Tyto dvě informace uložíme do konfiguračního souboru aplikace web.config. Provedeme to přidáním nových klíčů do elementu appSettings
, který k tomuto účelu vytvoříme:
<?xml version=“1.0″ encoding=“utf-8″ ?>
<configuration>
<appSettings>
<add key=“connStr“ value=“Data Source=server; Initial Catalog=db; User ID=sa; Password=“ />
<add key=“command“ value=“SELECT * FROM diskuse“ />
</appSettings>
…
Nezapomeňte samozřejmě do connection stringu zapsat skutečnou adresu serveru, název databáze a jméno uživatele s jeho heslem. Tato data pak načteme ve stránce takto:
private void Page_Load(object sender, System.EventArgs e)
{
string connStr =
ConfigurationSettings.AppSettings[„connStr“];
string command =
ConfigurationSettings.AppSettings[„command“];
K získání dat použijeme běžně používaný SqlDataAdapter
, který pak těmito daty naplní DataSet
:
SqlDataAdapter adapter =
new SqlDataAdapter(command, connStr);
DataSet data = new DataSet(„Diskuse“);
adapter.Fill(data, „Prispevek“);
adapter.Dispose();
Nakonec získaná data převedeme do XML dokumentu využitím třídy XmlDataDocument
. Tato třída je přímým potomkem XmlDocument
a umožňuje pracovat s DataSetem stejně jako s XML dokumentem. Toho využijeme, vytvoříme novou instanci z našeho DataSetu a přímo ji předáme XML webcontrolu jako vstupní dokument. Žádné další manipulace nejsou třeba, protože vše zařídí XML transformace. XML webcontrol se během renderování stránky postará sám o transformaci nad předaným dokumentem a výsledek přímo umístí do stránky na svou pozici.
this.Tree.Document = new XmlDataDocument(data);
}
Tímto je náš C# kód kompletní. Jak vidíte, samotné výkonné jádro obsahuje pouze sedm řádků a je použitelné na jakékoli data v jakémkoli formátu, protože je nijak přímo nezpracovává.
Transformace
Přistupme k poslednímu, avšak nejdůležitějšímu kroku, kterým je napsání transformačního stylesheetu diskuse.xsl. Protože vstupní dokument je zatím nezpracovaný, bude muset stylesheet analyzovat stromovou strukturu sám. Jak uvidíte níže, nebude to činit žádné potíže. Nejdříve se podívejme, jak mohou XML data vygenerovaná z DataSetu vypadat:
<Diskuse>
<Prispevek>
<ID>1</ID>
<autor>paya</autor>
<obsah>4all: Ahoj, jdeme na pivo?</obsah>
</Prispevek>
<Prispevek>
<ID>2</ID>
<pID>1</pID>
<autor>pierre</autor>
<email>ja@pierre.cz</email>
<obsah>OK, v 19h na Stodolní?</obsah>
</Prispevek>
…
</Diskuse>
Pole, které v databázi mají hodnotu NULL, se v XML dokumentu nevyskytují vůbec. Toho pak využijeme v transformaci.
Vstupním bodem stylesheetu bude šablona pro element Diskuse, která bude hledat kořenové příspěvky, to znamená ty, které neobsahují odkaz na rodiče – element pID
. To lze snadno otestovat predikátem count(pID)=0
. Příspěvky budou v HTML zobrazeny jako nečíslovaný seznam, proto je zabalíme do elementu ul
.
Jádro transformace bude tvořit šablona pro Prispevek. Tato šablona bude zobrazovat informace o příspěvku jako položku seznamu, její tělo tedy bude uzavřeno do elementu li
. Dále bude šablona zkoumat, zda příspěvek má nějaké odpovědi a pokud ano, vytvoří nový seznam (ul
), do nějž nechá rekurzivně zpracovat tyto odpovědi. Při hledání odpovědí bude porovnávat jejich pID
s hodnotou ID
aktuálního příspěvku.
Některé příspěvky nemají vyplněn e-mail autora, tuto skutečnost tedy budeme vyhodnocovat a pokud bude e-mail uveden, poskytneme jej přímo jako odkaz.
<?xml version=’1.0′?>
<xsl:stylesheet
xmlns:xsl=’http://www.w3.org/1999/XSL/Transform‘
version=’1.0′>
<xsl:template match=“Diskuse“>
<ul>
<xsl:apply-templates
select=“Prispevek[count(pID)=0]“ />
</ul>
</xsl:template>
<xsl:template match=“Prispevek“>
<li>
<h4>
<xsl:value-of select=“autor“ />
<xsl:if test=“email“>
<xsl:text> (</xsl:text>
<a href=“mailto:{email}“>
<xsl:value-of select=“email“ />
</a>
<xsl:text>)</xsl:text>
</xsl:if>
</h4>
<p><xsl:value-of select=“obsah“ /></p>
<hr/>
</li>
<xsl:if test=“/Diskuse/Prispevek[pID=current()/ID]“>
<ul>
<xsl:apply-templates
select=“/Diskuse/Prispevek[pID=current()/ID]“/>
</ul>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Chování při nekonzistenci dat
Pokud je v diskusi příspěvek odkazující se na neexistujícího rodiče, tento příspěvek nebude nikdy zobrazen, protože transformace postupuje od rodičů k potomkům a chybný příspěvek žádného rodiče nemá. Jinou chybou je příspěvek, který za svého přímého či nepřímého rodiče považuje sám sebe, například pokud příspěvek A odkazuje na B a zároveň B odkazuje na A. V takové situaci oba příspěvky vytvoří jakýsi ostrůvek oddělený od ostatních příspěvků, takže se k němu transformace opět nedostane a nedojde k žádnému zacyklení.
Epilog
Můžete si stáhnout celou aplikaci a vyzkoušet si ji. Ještě musím dodat, že toto řešení není úplně ideální, protože znemožňuje používání ASP.NET controlů uvnitř diskuse. Ve většině případů to však ani nepotřebujeme. Naopak velkou výhodou jsou vlastnosti stylesheetu – je přehledný, snadno upravitelný a lze využít celý sortiment XSLT a XPath funkčností nabízejících snadnou práci se strukturovanými daty.
Odkazy, zdroje
- Generujeme XML z MS SQL Serveru – Bříza, Petr (Interval.cz, 1. 4. 2004)
- Kompletní průvodce XSLT – Bříza, Petr (Interval.cz, nedatováno)
- SqlDataAdapter a zobrazení stromové struktury Repeaterem v ASP.NET – Růžička, Pavel (Interval.cz, 9. 7. 2004)
- SQLXML (MSDN library, nedatováno)
- The Extensible Stylesheet Language Family (XSL) (W3C, nedatováno)
- XSLT v příkladech – Jiří Kosek (www.kosek.cz, 26. 4. 2004)
Mohlo by vás také zajímat
-
Vaše pošta může být špatně nastavena – svěřte ji profesionálům
13. července 2023 -
4 tipy, jak na efektivní úsporu při rozjezdu podnikání
3. ledna 2023 -
AI na dosah ruky: Jak je to s AI v osobních zařízeních?
22. ledna 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024