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.
Poznáváme C# a Microsoft. NET 46. díl – použití XPath

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

To tu ještě nebylo. Specialisté ukázali, že zavirované mohou být i titulky SRT

To tu ještě nebylo. Specialisté ukázali, že zavirované mohou být i titulky SRT

** Stáhnete si film a titulky třeba z OpenSubtitles.org ** A osud vás za ten warez záhy potrestá ** Specialisté totiž ukázali, že i v titulcích může být schovaný virus

24.  5.  2017 | Jakub Čížek | 57

WannaCry se neměl vůbec rozšířit. Stačilo, abychom používali Windows Update

WannaCry se neměl vůbec rozšířit. Stačilo, abychom používali Windows Update

** WannaCry se masivně rozšířil kvůli zranitelnosti ve Windows ** Ta mu umožnila, aby se pokusil sám napadnout další počítače ** Jenže ta chyba už je dva měsíce opravená!

22.  5.  2017 | Jakub Čížek | 96


Aktuální číslo časopisu Computer

Bojujeme proti Fake News

Dva velké testy: fotoaparáty a NASy

Co musíte vědět o změně evropského roamingu

Radíme s výběrem základní desky