Avatar billede decrypto Nybegynder
10. oktober 2008 - 20:38 Der er 19 kommentarer og
1 løsning

Læse et xml dokument

Jeg har fået skrevet en del xpath udtryk, der henter nogle ting fra et xml dokument.

Det virker fint, men det virker ret usmart på den måde, jeg har fået lavet det.

Er der nogen herinde, der kan fortælle mig en smartere måde at lave det på?

Jeg har lavet det på følgende måde:
--------------------------------------------------------
private string Expr1 = "/first/result/name/text()";
private string Expr2 = "/first/result/charID/text()";
private string Expr3 = "/first/result/race/text()";
private string Expr4 = "/first/result/gender/text()";
private string Expr5 = "/first/result/bl/text()";
private string Expr6 = "/first/result/cpName/text()";

string filePath = "c:\mydoc.xml"

XPathNavigator nav;
XPathDocument docNav;
XPathNodeIterator NodeIter;

docNav = new XPathDocument(filePath);
nav = docNav.CreateNavigator();
NodeIter = nav.Select(Expr1);

Character character = new Character();
while (NodeIter.MoveNext()) {
  character.Name = NodeIter.Current.Value;
}
--------------------------------------------------------------

Nu er problemet jo at jeg har flere xpath udtryk, som hver henter noget data, jeg skal sætte ind i mit Character objekt, og at gentage alt dette virker forkert. Desuden virker det heller ikke smart at lave en lille privat metode, der ordner det.

Der må da være en bedre måde at læse noget xml data ind i et objekt på.

Er der nogen der kan hjælpe?
Avatar billede arne_v Ekspert
10. oktober 2008 - 20:42 #1
XPath er den helt fleksible måde at gøre det på.

Jeg ville nok lave det lidt anderledes.

en XPath som finder alle "records" i XML filen
iterer over dem
for hver af dem konstruer et Character object ved at en lille XPath for hver egenskab

Alternativt kan du kigge på f.eks. XML deserialisering.
Avatar billede decrypto Nybegynder
10. oktober 2008 - 21:00 #2
ja, jeg er nok lidt mere lun på xml deserialiseringen...

Jeg prøver lige den....hvis du har noget kodestump i baglommen, så smid det gerne herind :)
Avatar billede decrypto Nybegynder
10. oktober 2008 - 21:12 #3
Hmmmm det eksempel jeg lige kan finde, skal jeg angive en TypeOf...problemet er bare at det er stort xml dokument, hvoraf jeg blot skal bruge en lille del. Så jeg har ikke et naturligt objekt, som jeg kan 'mappe' xml data over. Hvis man kan gøre det uden at angive et specifikt objekt, så må jeg prøve med XPath eksemplet.
Avatar billede driis Nybegynder
10. oktober 2008 - 22:55 #4
Generelt er min erfaring at XML deserialization sjældent kan betale sig, med mindre XML dokumentet rent faktisk svarer til en af dine kendte klasser.

Du kan jo f.eks. lave en XPath der henter alle result noder - og derefter lave en metode som læser hver enkelt stykke data fra XML filen. Så er dit "overhead" ved at skrive konverteringen manuelt, begrænset.
Avatar billede decrypto Nybegynder
10. oktober 2008 - 23:21 #5
Jeg har nu valgt at udpege et segment af min xml kode og vil nu matche mine ting med mit objekt

XPathNavigator nav2 = iterator.Current.Clone();
character.Name = nav2.???; <- hvad kan man skrive her for at ramme lige nøjagtig <CharacterName>Navn</CharacterName> delen i min xml?
Avatar billede arne_v Ekspert
11. oktober 2008 - 02:07 #6
Prøv og se dette ekempel:

<all>
    <rec>
        <obj>
            <a>x</a>
            <b>y</b>
        </obj>
        <crap>bla bla</crap>
    </rec>
    <rec>
        <obj>
            <a>z</a>
            <b>w</b>
        </obj>
        <crap>mere bla bla</crap>
    </rec>
</all>

using System;
using System.Collections.Generic;
using System.Xml;

namespace E
{
    public class Data
    {
        public string A { get; set; }
        public string B { get; set; }
        public override string ToString()
        {
            return "[" + A + "," + B + "]";
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data> lst = new List<Data>();
            XmlDocument doc = new XmlDocument();
            doc.Load(@"C:\big.xml");
            foreach(XmlNode n in doc.SelectNodes("//all/rec/obj"))
            {
                lst.Add(new Data{ A=n.SelectSingleNode("a/text()").Value,
                                  B=n.SelectSingleNode("b/text()").Value});
            }
            foreach(Data d in lst)
            {
                Console.WriteLine(d);
            }
            Console.ReadKey();
        }
    }
}
Avatar billede decrypto Nybegynder
11. oktober 2008 - 10:13 #7
Jeg har fået lavet noget der ser fornftigt ud nu.

Jeg har lavet en statisk hjælpe klasse, der holder alle mine XPath udtryk som returneres som properties. I min anden klasse har jeg lavet en lille privat metode, der tager et XPath udtryk, og Xml dokument referencen som argument, og herfter returnerer det mig lige det, jeg har behov for. :)

Smid gerne et svar ind, da jeg i det mindste har fået noget inspiration.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 12:52 #8
Jeg har nu et andet spørgsmål...
Er det ikke muligt at lave et hieraki af statiske klasser?

Fx har jeg en statisk klasse, der hedder XPathHelper, hvori alle mine Xpath udtryk står i.
Jeg kunne dog tænkte mig at inddele mine udtryk. Fx. kunne det være lækkert at kunne skrive:

XPathHelper.Character.Name
XPathHelper.Skill.Description

Ideen er at jeg i min XPathHelper klasse på en eller anden måde kan angive 'Character' og 'Skill' som properties, hvor jeg kun bruger get. Get returnerer mig så fx. Character relaterede udtryk.

Kan det lade sig gøre?
Avatar billede arne_v Ekspert
11. oktober 2008 - 15:27 #9
Det kan du godt.

Det vil så fungere ligesom namespace.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 15:31 #10
Ok..har du et eksempel?
Ved ikke om det er det samme som nested static classes.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 15:38 #11
public static class XPathHelper{
        /// <summary>
        /// Gets the xpath expression for the characterId.
        /// </summary>
        public static string CharacterId {
            get { return "/result/characterID/text()"; }
        }
        /// <summary>
        /// Gets the xpath expression for the skilldescription.
        /// </summary>
        public static string CharacterId {
            get { return "/result/skillDescription/text()"; }
        }
}

De to forskellige Xpath udtryk vil jeg placere i henholdsvis en 'CharacterXPath' og en 'SkillXPath' som begge to er statiske.
I min XPathHelper, vil jeg så gerne have dem ind som proporties....noget a la:

public static class XPathHelper{
        /// <summary>
        /// Gets the character xpath.
        /// </summary>
        public static CharacterXPath CharacterXPath {
            get { return ????? }
        }
        /// <summary>
        /// Gets the xpath for skill.
        /// </summary>
        public static SkillXPath skillXPath {
            get { return ???? }
        }
}

Mine udtryk vil naturligvis stå i to filer nu, men kan tilgås via:
XPathHelper.Character.Name
XPathHelper.Skill.Description

Er meget spændt på at høre hvordan jeg kan få lavet det. Det vil strukturere mine udtryk endnu bedre, istedet for at have een fil med dem alle sammen i (der er mange).
Avatar billede arne_v Ekspert
11. oktober 2008 - 15:42 #12
Jeg tænker:

public class DinRigtigeKlasse
{
    public static class FoersteGruppe
    {
        public static string MethodA ...
        public static string MethodB ...
    }
    public static class AndenGruppe
    {
        public static string MethodC ...
        public static string MethodD ...
    }
    ...
    // bruge f.eks. AndenGruppe.MethodC
}
Avatar billede decrypto Nybegynder
11. oktober 2008 - 15:44 #13
Hmmm ok....så de står altså i samme fil.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 15:45 #14
Tror du man kan lave min hoved klasse som partial class...og så skrive den udenom mine underklasser? kan lige prøve det.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 15:51 #15
Jeps, partial virkede....men min hoved klasse ser nu ret tom ud :-(
men måske er det ok?
Avatar billede arne_v Ekspert
11. oktober 2008 - 15:53 #16
Du kan også smide dem i en anden fil.

namespace.ydreklasse.nestedklasse.metode
Avatar billede arne_v Ekspert
11. oktober 2008 - 15:53 #17
partial klasse er egengligt lavet til hvor noget af koden genereres, men det er en helt
standard feature i C# og kan bruges i andre sammenhænge også
Avatar billede decrypto Nybegynder
11. oktober 2008 - 16:01 #18
Ja, ideen ryger lidt på den måde...virker ret unødvendigt....man kan jo bare smide ned i et andet under namespace.

Smid bare et svar ind :=)
Avatar billede arne_v Ekspert
11. oktober 2008 - 17:36 #19
Nested static classes er reelt bare en anden form for namespaces.

Og et svar.
Avatar billede decrypto Nybegynder
11. oktober 2008 - 18:08 #20
Mange tak for inspiration...og gode ideer.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester