Linq to xml - budowanie zapytania

0

Witam

Mam następujący plik xml:

<?xml version="1.0" encoding="ISO-8859-2"?>
<lody>
<lodysmietankowe>
  <lod nazwa="Lod1" typwafla="001" uwagi="">    
    <kolor barwa="Zielona" dawka="1.25">	      
    <kolor barwa="Czerwona" dawka="1.25">	      
  </lod>
  <lod nazwa="Lod2" typwafla="002" uwagi="">
    <kolor barwa="Czerwona" dawka="1">
    <kolor barwa="Niebieska" dawka="0.75">
    <kolor barwa="Biala" dawka="2">    
  </lod>
</lodysmietankowe>
</lody>

Oczywiście lodów może być całe mnóstwo, z różnymi kolorami i dawkami kolorów. Chciałbym pobierać określone dane z takiego pliku. Najprostsze przypadki opracowałem, np. wybieranie wszystkich lodów, czy też loda o nazwie Lod123. Opracowałem także zapytanie do wybierania lodów zawierających dany kolor, jednak mam problem, jeżeli kolor o który mi chodzi nie jest pierwszym węzłem od góry. Czyli np. chciałbym wybrać lody z kolorem białym - jak to zrobić? Jak zrobić, żeby wybrać wszystkie kolory i dawki ze wszystkich lodów zawierających kolor biały w dawce 2 lub większej?

Prosiłbym o chociaż jedną odpowiedź, resztę postaram opracować na jej podstawie.
Pozdrawiam i z góry dziękuję

0

Czesc :)
Jako, ze dzis sie w pracy nudze, a i tez ucze sie LinQ, tak pobawilem sie z Twoim problemem.
Po pierwsze, Twoj xml jest niepoprawny <kolor> nie posiada domykajacych go klamer badz tez slasha na koncu <kolor /> .

Moje dzialajace rozwiazanie to:

			Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-Us"); // np w kulturze pl przecinek w ulamkowej czesci jest przecinkiem, a w xml'u mamy kropke
			StreamReader reader = File.OpenText("Test.xml");
			XDocument xDoc = XDocument.Load(reader);
			var result = (from lod in xDoc.Descendants("lod")
						  where lod.Elements("kolor").Attributes("barwa").Any(w => w.Value == "Biala") && lod.Elements("kolor").Attributes("dawka").Any(d => Convert.ToDouble(d.Value) >= 2)
						  select new Lod
						  {
							  Nazwa = lod.Attribute("nazwa").Value,
							  TypWafla = lod.Attribute("typwafla").Value,
							  Uwagi = lod.Attribute("uwagi").Value,
							  Typ = lod.Parent.Name.LocalName,
							  Kolory = (from kolor in lod.Elements("kolor")
										select new Kolor
										{
											Barwa = kolor.Attribute("barwa").Value,
											Dawka = Convert.ToDouble(kolor.Attribute("dawka").Value)
										}).ToList()
						  });



public class Lod
	{
		public string Nazwa { get; set; }
		public string TypWafla { get; set; }
		public string Uwagi { get; set; }
		public List<Kolor> Kolory { get; set; }
		public string Typ { get; set; }
	}

	public class Kolor
	{
		public string Barwa { get; set; }
		public double Dawka { get; set; }
	}

Jesli ktos mialby lepsze rozwiazanie to z checia bym je poznal :)
Co do samego xmla i bawienia sie z LinQ, to o wiele prosciej bylo by uzyc standardowej deserializacji dostepnej dla klas... no ale jak wiadomo, nie zawsze mozemy kontrolowac w jaki sposob xml jest serializowany (np. utknalem na problemie potrojnej tablicy, ktorej z .net'a zdeserializowac sie nie dalo, a klient akurat takim xml'em operowal).

0

Witam ponownie

Pięknie dziękuję! Szczególnie za zwrócenie mi uwagi na CultureInfo.
Mógłbyś rzucić jakieś linki gdzie bardziej szczegółowo traktuje się sprawy tworzenia zapytań?
Dzięki raz jeszcze, idę tworzyć na tej bazie dalsze zapytania :)

Pozdrawiam

0

Szczerze to sam ucze sie metoda prob i bledow, wiec zadnego konkretnego linku nieposiadam.

Pomocny do tego jest LinQPad, acz on niestety nie wspiera xml'a ale za to do budowania zapytan na bazie danych jest wrecz nieoceniony.

0

heh zrobilem identyczny kod roznica tylko polegala na tym ze uzylem typow anonimowych, zamiast Convert dalem double.Parse i zamiast StreamReader wrzucilem Od razu plik.

XDocument doc = XDocument.Load(@"~/XMLFile1.xml");

ja poznalem linq to xml z tej stronki ;]
http://xml.com.pl/show/polish/linq_to_xml.aspx
skarbnica wiedzy nie jest ale na pierwszy rzuc oka wystarcza ;]
oraz jeden filmik gdzies dorwalem "WinVideo-Orcas-LINQToXML.wmv" tak sie nazywa ten plik z google znajdziesz

Co do linqPad oczywiscie ze jest super tylko za intelisense trzeba placic i tym sposobem juz wole zrobic sobie ConsoleAplication i wszystko tam sprawdzic :].

0

Witam ponownie

Zaimplementowałem już linq w moim programiku, i chciałbym tylko dodać, że postanowiłem, zamiast listy klas, trzymać dictionary stringów (wydaje mi się, że zwiększy to wydajność):

Kolory = lod.Elements("kolor").ToDictionary(x => x.Attribute("barwa").Value,
x => x.Attribute("dawka").Value)

Pozdrawiam

0

Witam ponownie

To jeszcze raz ja :)
Aplikacja się ładnie buduje, cały czas dodaję nową funkcjonalność i stanąłem na problemie usuwania elementów.

Powiedzmy, że mam plik w kształcie:

<Lody>
   <Lod nazwa="1" />
   <Lod nazwa="2" />
   <Lod nazwa="3"/>
</Lody>

I teraz chciałbym usunąć lód o nazwie "2". Zabieram się do tego następująco:

XElement xElem = XElement.Load(path);

I teraz mógłbym: xElem.Element("Lod").Remove();
Ale to nie da mi odpowiednich wyników. Czy są jakieś inne, bardziej szczegółowe, funkcje Remove, czy też może należy to robić jakoś inaczej (jak? przypomnę, że chodzi mi o linq, nie xpath czy inne techniki).

Pozdrawiam i z góry dzięki za odpowiedź

0

Silly me...

XElement xElem = XElement.Load("lody.xml");
xElem.Elements("Lod").Where(s => s.Attribute("nazwa").Value == "2").Remove();
0

dodam tylko ze mozesz edytowac swoj post, a nie pisac jeden pod drugim.

0

Jak widać w moim poprzednim poście, zdaję sobie sprawę z tej funkcji.
Napisałem oddzielnego posta ponieważ uznałem, iż tak będzie lepiej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1