Poznáváme C# a Microsoft. NET 46. díl – použití XPath

Další díl tohoto seriálu bude opět poletovat okolo problematiky XML. Dnes se podíváme na možné použití jazyka XPath v prostředí .NET.

Jazyk XPath

Tento jazyk byl jako standard vydán v roce 1999 světovým konsorciem W3C. Tento jazyk zjednodušeně řečeno, mimo jiné, umožňuje pomocí své dotazové syntaxe vyjádřit, která množina uzlů má být získána. Jinak řečeno, pomocí použití tohoto jazyku jsme schopni vybrat určitou množinu dat na základě specifických podmínek.

Jazyk XPath je kromě jiného jednou z největších „pomocníků“ při používání XSL transformací. Nechci se v tomto díle zabývat popisem tohoto ne zrovna triviálního jazyku a proto případné zájemce o učení se odkážu na jeden výborný tutoriál, který naleznete na adrese http://www.w3schools.com/xpath/.

Užití XPath v .NET

Pro naše ukázkové příklady budeme opět používat náš známý XML dokument obsahující data o zaměstnancích.

<?xml version="1.0" encoding="utf-8" ?>
<zamestnanci>
  <zamestnanec jmeno="Michal" prijmeni="Racek" pozice="Vyvojar"/>
  <zamestnanec jmeno="Jan" prijmeni="Novak" pozice="Analytik"/>
  <zamestnanec jmeno="Jiri" prijmeni="Joudek" pozice="Vyvojar"/>
</zamestnanci>

Zkusme se zamyslet nad situací, kdy chceme najít nějakého konkrétního zaměstnance, tedy například podle příjmení. Bez použití jazyku XPath s použitím přístupu přes DOM bychom takovýto požadavek splnili možná podobným způsobem jako je ten následující.

/// <summary>
/// Vyhleda uzel zamestnance podle prijmeni
/// </summary>
/// <param name="Prijmeni">Prijmeni hledaneho zamestnance</param>
internal static void HledaniZamestnanceBezXPath(string Prijmeni)
{
  //ziskani cesty odkud je aplikace spustena
  string lPath = AppDomain.CurrentDomain.BaseDirectory + "zamestnanci.xml";
  XmlDocument lDoc = new XmlDocument();
  lDoc.Load(lPath);
  XmlNode lRootElem = lDoc.DocumentElement;
  foreach(XmlNode lNode in lRootElem)
{
    if (lNode.Name.Equals("zamestnanec"))
    {
      foreach (XmlAttribute lAttribute in lNode.Attributes)
      {
        if (lAttribute.Name.Equals("prijmeni") && lAttribute.Value.Equals(Prijmeni))
          {
          Console.WriteLine("Hledany zamestanec : {0} {1} - {2}", lNode.Attributes["jmeno"].Value, lNode.Attributes["prijmeni"].Value, lNode.Attributes["pozice"].Value);
        }
      }
    }
  }
}

public static void HledaniBezXPath()
{
  HledaniZamestnanceBezXPath("Joudek");
}

Tento příklad samozřejmě bude funkční, ale je poněkud složitý a navíc takovýto přístup k vyhledávání uzlů je v případě, kdy jsou hledané uzly závislé na složité hierarchii rodičovských uzlů, také dost náchylné k chybám. Zkusme tento požadavek naimplementovat nějak elegantněji. Samozřejmě mám na mysli s použitím XPath.

public static void HledaniXPath()
{
  HledaniZamestnanceXPath("Joudek");
}

/// <summary>
/// Vyhleda uzel zamestnance podle prijmeni pouzitim XPath
/// </summary>
/// <param name="Prijmeni">Prijmeni hledaneho zamestnance</param>
internal static void HledaniZamestnanceXPath(string Prijmeni)
{
  string lPath = AppDomain.CurrentDomain.BaseDirectory + "zamestnanci.xml";
  XmlDocument lDoc = new XmlDocument();
  lDoc.Load(lPath);
  //sestaveni XPath dotazu
  string lXPathQuery = "descendant::zamestnanec[@prijmeni=`" + Prijmeni + "`]";
  //vyvolani XPath dotazu
  XmlNodeList lResult = lDoc.SelectNodes(lXPathQuery);
  if (lResult.Count > 0)
  {
    XmlNode lResultNode = lResult[0];
    Console.WriteLine("Hledany zamestanec : {0} {1} - {2}", lResultNode.Attributes["jmeno"].Value, lResultNode.Attributes["prijmeni"].Value, lResultNode.Attributes["pozice"].Value);
  }
}

Po sestavení XPath dotazu, k jeho spuštění a získání výsledku v podobě XMLNodeListu, použijeme metodu SelectNodes, která je definována již na předkovi třídy XMLDocument, tedy na třídě XMLNode. Po té již jednoduše procházíme výsledný list uzlů.

Rozhraní XPath a třída XPathNavigator

Kromě výše zmíněného způsobu spuštění XPath dotazu, existuje ještě jedna cesta, která je představována použitím nějaké implementace rozhraní IXPathNavigable. Toto rozhraní je implementováno také třídou XMLNode. Rozhraní předepisuje jednu jedinou metodu, kterou je CreateNavigator. Tato metoda vrací odkaz na instanci třídy XPathNavigator, která umožňuje číst data pomocí kurzorového modelu (posuny kurzoru na určité části dat). Následující příklad ukazuje jak na to pomocí užití výše zmíněné třídy.

/// <summary>
/// Ukazka pouziti dotazu XPath pomoci tridy XPathNavigator
/// </summary>
public class XPathNavigatorExam
{
  /// <summary>
  /// Vyhleda uzel zamestnance podle pozice pouzitim XPath
  /// </summary>
  /// <param name="Pozice">Pozice hledanych zamestnancu</param>
  internal static void HledaniZamestnance(string Pozice)
  {
    string lPath = AppDomain.CurrentDomain.BaseDirectory + "zamestnanci.xml";
    XmlDocument lDoc = new XmlDocument();
    lDoc.Load(lPath);
    XPathNavigator lNavigator = lDoc.CreateNavigator();
    string lXPathQuery = "descendant::zamestnanec[@pozice=`" + Pozice + "`]";
    //zkompilujeme XPath dotaz
    XPathExpression lCompiledQuery = lNavigator.Compile(lXPathQuery);
    //provedeme dotaz
    XPathNodeIterator lIterator = lNavigator.Select(lCompiledQuery);
    //zobrazime vysledky
    while(lIterator.MoveNext())
    {
      //vytvorime klon navigatoru
      XPathNavigator lClonedNavigator = lIterator.Current.Clone();
      //posun na prvni uzel
      lClonedNavigator.MoveToFirstChild();
      //posun na atribut jmeno
      lClonedNavigator.MoveToAttribute("jmeno","");
      string lJmeno = lClonedNavigator.Value;
      //posun na dalsi atribut, kterym je prijmeni
      lClonedNavigator.MoveToNextAttribute();
      string lPrijmeni = lClonedNavigator.Value;
      Console.WriteLine("{0} {1}", lJmeno, lPrijmeni);
    }
  }
public static void NajdiZamestnance()
  {
    HledaniZamestnance("Vyvojar");
  }
}

Po získání odkazu na instanci třídy XPathNavigator, můžeme XPath dotaz zkompilovat pomocí jeho metody Compile, jejíž návratová hodnota je typu XPathExpression, která slouží právě k reprezentaci kompilovaných výrazů jazyku XPath. Po zavolání metody Select na instanci třídy XPathNavigator získáme odkaz na instanci třídy XPathNodeIterator, který následně použijeme k průchodu vybranými uzly.

Při každé iteraci listem, vytvoříme klon instance třídy XPathNavigator a to z důvodu abychom posouvali kurzor na speciální instanci. Po té na tomto klonu voláme metody (MoveToFirstChild, MoveToAttribute, MoveToNextAttribute) k zajištění posunu kurzoru na námi chtěné pozice. Obsah kurzoru si na dané pozici přečteme skrze instanční vlastnost Value třídy XPathNavigator.

Příklady k článku naleznete zde.

Témata článku: Software, Microsoft, Programování

1 komentář

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:42:06
    Programovou oflline verzi seriálu naleznete ke stažení na...
Určitě si přečtěte

Monitory do 10 tisíc: poradíme, jaké jsou teď nejlepší

Monitory do 10 tisíc: poradíme, jaké jsou teď nejlepší

** Dobrý monitor s kvalitním panelem lze pořídit pod tři tisíce korun ** Pod deset tisíc si můžete koupit pracovní 27" monitor nebo nejlevnější použitelné 4K ** Vybrali jsme také ideální model pro vícemonitorovou konfiguraci

27.  11.  2016 | Stanislav Janů | 13

Sbíječky vyměnili za klávesnice. Nový projekt má za cíl přeučit horníky na programátory

Sbíječky vyměnili za klávesnice. Nový projekt má za cíl přeučit horníky na programátory

** Programátorů je málo a horníků bez práce po uzavření dolu Paskov bude moc ** Problém řeší unikátní projekt ** Pilotní kurz dává naději, že by z horníků mohli být použitelní kodéři

28.  11.  2016 | David Polesný | 76