Avatar billede jackass- Nybegynder
22. november 2010 - 13:45 Der er 18 kommentarer og
1 løsning

Parse XML fra webservice

Hej,

Jeg har følgende webservice som returnerer rækker fra en MS SQL database:

[WebMethod(Description = "Fetch from SQL database.")]
public System.Xml.XmlDocument GetCopyJobs()
{
    string sqlStr = "SELECT * FROM Table";
    SqlConnection conn = new SqlConnection(connectionString);
    DataSet dsCopyJobs = new DataSet();
    SqlDataAdapter daCopyJobs = new SqlDataAdapter(sqlStr, conn);
    daCopyJobs.Fill(dsCopyJobs);

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(dsCopyJobs.GetXml());
    return xmlDoc;
}

Og det virker fint når jeg tester webservicen, XML vises osv. Men hvordan viser/parser jeg resultatet, altså rows og fields fra tabellen i mit prog?

private void button1_Click(object sender, EventArgs e)
{
    MyWebservice.Service client = new MyWebservice.Service();
    DataSet dsCopyJobs = new DataSet();
    XmlElement element = client.GetCopyJobs();

    ...how to parse the xml element as "sql rows"?..
}

Håber nogen kan hjælpe :-/
Avatar billede Syska Mester
22. november 2010 - 13:55 #1
Hvordan ser XML dokumentet ud ... det ville være en stor hjælp.

mvh
Avatar billede jackass- Nybegynder
22. november 2010 - 14:19 #2
Naturligvis :-) Her er noget af den:

  <?xml version="1.0" encoding="utf-8" ?>
- <NewDataSet>
- <Table>
  <rowid>1</rowid>
  <copyfrom>H:\public</copyfrom>
  <copyto>%SYSTEMDRIVE%\Program Files\MyApp\Config</copyto>
  <enabled>1</enabled>
  </Table>
- <Table>
  <rowid>3</rowid>
  <copyfrom>H:\MyFiles</copyfrom>
  <copyto>%SYSTEMDRIVE%\Program Files\MyApp\files</copyto>
  <enabled>1</enabled>
  </Table>
- <Table>

Dybest set vil jeg jo gerne kunne læse "copyfrom", "copyto" og "enabled" i stedet for at sql select direkte mod databasen, som jeg gør idag.
Avatar billede janus_007 Nybegynder
22. november 2010 - 16:50 #3
buzzz er måske faldet i søvn.

Det er lidt underligt det du prøver, men måske jeg ikke lige helt forstår :)
Det nemmeste vil være hvis du returnere en string istedet for.. men pyt.

Gør sådan her:
var nodeReader = new XmlNodeReader(xmlDocument)
nodeReader.MoveToContent();
var xDoc = XDocument.Load(nodeReader);

Så har du konverteret XmlDoc til XDoc, imho er langt nemmere at arbejde med.

var copyJobs = xDoc.Root.Elements("Table").Select(x => new { RowId = x.Element("rowid").Value, CopyFrom = x.Element("copyfrom").Value, CopyTo = x.Element("copyto").Value });


Så har du en fin anonym type, hvad der herefter skal ske har du ikke beskrevet :)
Avatar billede bvli Praktikant
22. november 2010 - 19:55 #4
hvis du reelt bare skal have en kopi af det dataset du returnerer fra webservicen, så er det letteste nok noget a'la:

[...]
MyWebservice.Service client = new MyWebservice.Service();
DataSet dsCopyJobs = new DataSet();
XmlDocument document = client.GetCopyJobs();
using (Stream s = new MemoryStream()) {
  element.Save(s);
  s.Position = 0;
  dsCopyJobs.ReadXml(s);
}
Avatar billede bkp Nybegynder
22. november 2010 - 22:28 #5
Hvorfor ikke bruge interface / klasse istedet for XML, hvis den er public i din webservice, så er den også gyldig som datagrundlag.

Alternativt kunne du bruge Json, det er uhyre nemt at parse.
Avatar billede arne_v Ekspert
23. november 2010 - 02:42 #6
Jeg vill ændre return værdi for den web service fra XmlDocument til String.

Så kan client hente den String og bruge XmlDocument LoadXml eller XDocument Parse efter behag.
Avatar billede bkp Nybegynder
23. november 2010 - 07:39 #7
Jeg har selv en løsning godt nok til noget Ajax / jQuery, men her benytter jeg Json som i mange tilfælde fylder mindre end XML og er faktisk utrolig nemt at arbejde med, måske kan du bruge nedenstående funktioner:
public static string JsonCreate<T>(T serializableObject, bool doEncode) where T : class
{
    var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
    var ms = new MemoryStream();
    serializer.WriteObject(ms, serializableObject);
    var json = Encoding.UTF8.GetString(ms.ToArray());
    return doEncode ? HttpUtility.HtmlEncode(json) : json;
}

public static T JsonParse<T>(string jsonData, bool doDecode) where T : class
{
    if (doDecode) jsonData = HttpUtility.HtmlDecode(jsonData);
    using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonData)))
    {
        var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
        return serializer.ReadObject(ms) as T;
    }
}
Avatar billede bkp Nybegynder
23. november 2010 - 07:50 #8
Jeg vil tro at du kan bruge følgende kode op imod Jason funktionerne ovenfor:
//Danne json streng
var data = dsCopyJobs.Tables[1];
var jsonStr = JsonCreate<DataTable>(data, true);

//Danne Datatable fra Json string
DataTable data2 = JsonParse<DataTable>(jsonStr, true);
Avatar billede jackass- Nybegynder
23. november 2010 - 08:20 #9
Hold da op.. Mange tak for alle ideerne. Det lyder til at det nemmest vil være at returnere en string i stedet, så det har jeg ændret webservicen til.

Det jeg egentlig skal bruge det til er; Idag laver jeg SQL kaldet direkte fra klienten og looper igennem resultat rows og gør forskellige ting, med dette:

SqlDataReader dataReaderCopy = FunctionSqlDataReader(connectionString, "SELECT * FROM Jobs_Copy");
if (dataReaderCopy != null && dataReaderCopy.HasRows)
    {
    while (dataReaderCopy.Read())
      ...DO STUFF


..og det virker fint. Men i stedet ville jeg gerne bruge webservices, så logikken kan ændres/opdateres ét sted i stedet for i selve klienten.

Jeg har nu ændret webservicen så den returnerer string:

    [WebMethod(Description = "It will fetch copy jobs from SQL database.")]
    public string GetCopyJobs()
    {
        string sqlStr = "SELECT * FROM Jobs_Copy";
        SqlConnection conn = new SqlConnection(connectionString);
        DataSet dsCopyJobs = new DataSet();
        SqlDataAdapter daCopyJobs = new SqlDataAdapter(sqlStr, conn);
        daCopyJobs.Fill(dsCopyJobs);

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(dsCopyJobs.GetXml());
        string result = xmlDoc.InnerXml;
        return result;
    }


Og i min klient har jeg så indtil videre dette:


        private void button1_Click(object sender, EventArgs e)
        {
            MyWebservice.Service client = new MyWebservice.Service();
            string wsDoc = client.GetCopyJobs().ToString();

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(wsDoc);
        }

Altså er resultatet pt i et XmlDocument.

Hvordan kan jeg derfra "loope" gennem noderne ligesom jeg hidtil har gjort med "while (dataReaderCopy.Read())" hvor jeg har kunnet bruge DB indholdet ved dataReaderCopy[1].ToString(), dataReaderCopy[2].ToString() osv?

Beklager at den ikke er sevet ind, har ikke helt fanget logikken endnu :-/
Avatar billede bvli Praktikant
23. november 2010 - 09:45 #10
Janus gav dig svaret tidligere og hvis du vælger at returnere som string er det endda lettere:

XDocument xDoc = XDocument.Parse(resultatFraDitWebServiceKald);

Og så som Janus skrev:

"var copyJobs = xDoc.Root.Elements("Table").Select(x => new { RowId = x.Element("rowid").Value, CopyFrom = x.Element("copyfrom").Value, CopyTo = x.Element("copyto").Value });"



Når du så skal iterere over den bruger du:

foreach (var entry in copyJobs) {
  Console.WriteLine("RowId = " + entry.RowId);
  Console.WriteLine("CopyFrom = " + entry.CopyFrom);
  Console.WriteLine("CopyTo = " + entry.CopyTo);
}
Avatar billede jackass- Nybegynder
23. november 2010 - 11:24 #11
Webservicen returnerer nu string, men hvis jeg gør følgende i klienten:

MyWebservice.Service client = new MyWebservice.Service();
string wsDoc = client.GetCopyJobs().ToString();

XDocument xDoc = XDocument.Parse(wsDoc);
var copyJobs = xDoc.Root.Elements("Table").Select(x => new { RowId = x.Element("rowid").Value, CopyFrom = x.Element("copyfrom").Value, CopyTo = x.Element("copyto").Value, IsEnabled = x.Element("enabled").Value });

Men får følgende fejl:

'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' could be found (are you missing a using directive or an assembly reference?)

I usings har jeg pt:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Web.Services;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Win32;
Avatar billede jackass- Nybegynder
23. november 2010 - 11:31 #12
Hov, manglede lige System.Linq; - nu virker det :)

Men, når jeg kører programmet og trykker på min button1, får jeg følgende exception:

{"There is an error in XML document (1, 3253)."}

XML'en ser sådan ud:


<?xml version="1.0" encoding="utf-8" ?>
  <string xmlns="http://umupdaterweb/"><NewDataSet><Table><rowid>1</rowid><copyfrom............OSV OSV OSV og slutter med: </enabled></Table></NewDataSet></string>
Avatar billede jackass- Nybegynder
23. november 2010 - 12:14 #13
Jeg har smidt den tekst string som webservicen returnerer ind i http://www.xmlvalidation.com/ som ingen fejl finder? :-/
Avatar billede bvli Praktikant
23. november 2010 - 13:18 #14
hvad står der på linie 1, position 3253? (og deromkring)
Avatar billede jackass- Nybegynder
23. november 2010 - 13:56 #15
Hmm.. ingenting.. XML strengen er kun 2989 katakterer.. WTF? :-/
Avatar billede jackass- Nybegynder
23. november 2010 - 14:09 #16
Aber doch!!

Problem solved! Problemet var tilsyneladende at webservicen var added som en "Web Reference" i min klient og efterfølgende instansieret med:

MyWebservice.Service client = new MyWebservice.Service();

Efter i stedet at have added webservicen som "Service Reference" i Solution Explorer, og kaldt den med:

MyWebservice.ServiceSoapClient client = new MyWebservice.ServiceSoapClient();

..virker det hele! :-D

Det man så kan undre sig over, er hvad "Web Reference" så eksisterer for..

Tak til alle for det resterende og ikke mindst janus og bvli for den løsning der blev brugt :-P
Avatar billede jackass- Nybegynder
23. november 2010 - 14:12 #17
Lægger I et svar? :)
Avatar billede bvli Praktikant
23. november 2010 - 14:15 #18
WebReference er fra tiden før WCF. (det man normalt kalder 'old style asmx webservices')

Og et svar :)
Avatar billede Syska Mester
23. november 2010 - 16:29 #19
#janus_007

Hah, ja ... det kan man vist godt sige jeg var :-)
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