11 messaggi dal 19 marzo 2013
Buonasera a tuti,

Sto per creare la mia prima applicazione che usa un database in xml, quindi no conosco molto il linguaggio.

Mi piacerebbe indicare alla mia applicazione da che nodo figlio ricavare i dati da elaborare.
Potreste darmi delle indicazioni per favore?
Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
un documento XML può essere interrogato proprio come un database. A parte la natura gerarchica dei dati XML, la differenza è che al posto del linguaggio SQL si usa XPath.
Qui trovi un'introduzione alla sintassi:
http://www.w3schools.com/xpath/xpath_syntax.asp

karontenero ha scritto:
Mi piacerebbe indicare alla mia applicazione da che nodo figlio ricavare i dati da elaborare

Ok, la tua applicazione potrà fornire una stringa XPath come "provincia/comune" per selezionare tutti i nodi "comune" che siano diretti discendenti di "provincia".

Oppure potrà fare delle ricerche. Passando "//provincia[starts-with(@nome, "P")]", potrà ottenere tutti i nodi "provincia", ovunque si trovino, il cui attributo "nome" inizia per "P".

Se invece non ti interessa lavorare direttamente con i nodi XML, ma ti piacerebbe programmare con un modello orientato agli oggetti, allora puoi lasciar perdere XPath e dare un'occhiata a Linq to XML. Se già conosci la sintassi di interrogazione Linq, accedere ai dati sarà più semplice. Ecco la stessa ricerca di prima in Linq To XML. Forse questa è un po' più espressiva e mi dà anche la possibilità di proiettare i nodi risultanti su un mio tipo "Provincia".
var province = from provincia in xmlDoc.Descendants("provincia")
                            where provincia.Attribute("Nome").Value.StartsWith("P")
                            select new Provincia { Nome = provincia.Attribute("Nome") };


Qui hai un video di Stefano Mostarda su Linq to XML, molto informativo.
http://media.aspitalia.com/screencast/LINQ-to-XML-introduzione.media

Qui invece c'è un articolo che mette a confronto i due approcci.
http://msdn.microsoft.com/it-it/library/bb675156.aspx

ciao
Modificato da BrightSoul il 23 giugno 2013 13.53 -

Enjoy learning and just keep making
11 messaggi dal 19 marzo 2013
Ciao,
Grazie di avermi risposto.
Il mio problema e' questo: riferendomi al tuo esempio devo salvare in una lista tutti i paesi contenuti in un determinato comune di una determinata provincia.
Ti posto il mio xml:

<canaliorologio>
<canale id="1">
<TipoGiorno id="feriale">
<ora Start="0850" Stop="1018" />
<ora Start="1800" Stop="2100" />
</TipoGiorno>
<TipoGiorno id="pre festivo">
</TipoGiorno>
<TipoGiorno id="festivo">
</TipoGiorno>
</canale>

<canale id="12">
<TipoGiorno id="feriale">
<ora Start="0950" Stop="1030" />
<ora Start="1900" Stop="2300" />
</TipoGiorno>
</canale>
<TipoGiorno id="pre festivo">
</TipoGiorno>
<TipoGiorno id="festivo">
</TipoGiorno>
</canaliorologio>

Vorrei salvare in una lista tutti i valori di Start contenuti all' interno di Tipogiorno= feriale figlio di canale id= 12.

Al momento sono riuscito a fare solo questo:

var canale = xmlDoc.Root.Descendants("canale")
.Where(x => x.Attributes()
.Any(a => a.Name == "id" && a.Value.Equals("12")))
.ToList();


Con il quale vedo in una lista tutto il conenuto del canale, ma non riesco a specificare il tipo di giorno.

Potresti aiutarmi per favore?
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

karontenero ha scritto:

vedo in una lista tutto il conenuto del canale, ma non riesco a specificare il tipo di giorno.

ok, la tua query restituisce il canale giusto, è un buon inizio. Bisogna continuarla andando ad interrogare i suoi TipoGiorno e infine leggere i suoi nodi ora.

Prova così:
var idCanale = "12";
var idTipoGiorno = "feriale";
var elencoStart = xmlDoc
    //di tutti i canali
    .Descendants("canale")
    //prendo quelli che hanno l'idCanale indicato
    .Where(canale => canale.Attribute("id").Value == idCanale)
    //e poi estraggo tutti i loro TipoGiorno
    .SelectMany(canale => canale.Elements("TipoGiorno"))
    //tra i tanti, scelgo quelli che hanno l'idTipoGiorno indicato
    .Where(tipoCanale => tipoCanale.Attribute("id").Value == idTipoGiorno)
    //poi seleziono tutti i loro elementi ora
    .SelectMany(tipoCanale => tipoCanale.Elements("ora"))
    //e proietto solo l'attributo Start
    .Select(ora => ora.Attribute("Start").Value);                     

//adesso posso legare l'elenco ad un controllo ASP.NET
repeater1.DataSource = elencoStart;
repeater1.DataBind();

Qui vedi in azione il metodo SelectMany, che serve a generare molteplici risultati (da 0 a n) per ogni elemento dell'insieme. Il caso è quello dei tanti elementi ora che scaturiscono da ogni TipoGiorno.

ciao

Enjoy learning and just keep making
11 messaggi dal 19 marzo 2013
Ciao,
Grazie del tuo aiuto,

Quindi tramite questa query mi ricavo la lista dei valori di start, giusto?
C'e' una cosa che non mi torna: in debug se vado a visualizzare il contenuto di elencostart, mi viene restituito questo: {System.Linq.Enumerable.WhereSelectEnumerableIterator<System.Xml.Linq.XElement,string>}. come mai?

Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,
karontenero ha scritto:

Quindi tramite questa query mi ricavo la lista dei valori di start, giusto?

sì, esatto. Hai già provato, funziona?

karontenero ha scritto:

mi viene restituito questo, come mai?

Prova a poggiare il mouse sull'ultimo metodo Select: vedrai che il suo tipo di ritorno è un IEnumerable<string>.
E' perfetto così, perché si tratta di un elenco di stringhe che potrai ciclare un foreach oppure usarlo come data source per qualche controllo.

In realtà, il tipo di oggetto che Select ritorna, non è esattamente un IEnumerable<string> perché IEnumerable è solo un'interfaccia, ovvero un "contratto" che i tipi concreti possono implementare.
Non potendo fare new IEnumerable<string>(), il metodo Select sceglie di restituirti un oggetto di tipo WhereSelectEnumerableIterator<System.Xml.Linq.XElement,string> che viene usato internamente per garantirti query componibili senza per questo pesare sulle prestazioni.
Comunque è una roba che riguarda il funzionamento interno di LINQ, non te ne curare. Per il principio di sostituzione di Liskov, tutto quello che ti serve sapere è che quel tipo di ritorno implementi IEnumerable<string>. Non ha importanza quale sia la sua logica interna.

Invece, se ti chiedi come mai oltre a string venga menzionato anche il parametro di tipo XElement, questo dipende dal funzionamento del metodo Select. Essendo un metodo di proiezione, ovvero che trasforma oggetti di un tipo in nuovi oggetti di un altro tipo (dall'XElement "ora" alla stringa "Start", in questo caso) ha bisogno di conoscere il tipo di oggetto che riceverà in input e quello che fornirà come risultato.

ciao
Modificato da BrightSoul il 28 giugno 2013 23.18 -

Enjoy learning and just keep making
11 messaggi dal 19 marzo 2013
Ciao!!
Scusami ma non capisco, ho passato il mouse sull' ultimo select, ma non vedo i valori di orastart.
Mi servono perché dopo devo ordinarli in ordine crescente, confrontarli con una variabile contenente l'ora corrente per trovare il valore appena piu' piccolo e il suo relativo valore di orastop.
questa seconda parte penso di avere capito come risolverla, solo che vorrei prima capire dove trovo i valori da ordinare in ordine crescente

Ti ringrazio per l'auito che m stai dando
Se lavori con XML consiglio l'utilizzo di questo tool:

http://xsd2code.codeplex.com/

Fabrizio Canevali

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.