2016-08-08 3 views
0

moodle Webサービスから受け取ったXMLレスポンスを逆シリアル化しようとしています。XMLをC#(ドットネット)オブジェクトにパースする

id、shortname、idnumberなどの別個の名前付き属性があれば、それをドットネットオブジェクトに解析できますが、実際のフィールド名を持つKEY属性の配列があり、その内部に別のノードがありますフィールド値を有する。ここで

はサンプルです:

<?xml version="1.0" encoding="UTF-8" ?> 
     <RESPONSE> 
      <MULTIPLE> 
      <SINGLE> 
       <KEY name="id"> 
        <VALUE>2</VALUE> 
       </KEY> 
       <KEY name="shortname"> 
        <VALUE>CS-101</VALUE> 
       </KEY> 
       <KEY name="fullname"> 
        <VALUE>CS-101</VALUE> 
       </KEY> 
       <KEY name="enrolledusercount"> 
        <VALUE>2</VALUE> 
       </KEY> 
       <KEY name="idnumber"> 
        <VALUE></VALUE> 
       </KEY> 
       <KEY name="visible"> 
        <VALUE>1</VALUE> 
       </KEY> 
       <KEY name="summary"> 
        <VALUE>&lt;p&gt;CS-101&lt;br /&gt;&lt;/p&gt;</VALUE> 
       </KEY> 
       <KEY name="summaryformat"> 
        <VALUE>1</VALUE> 
       </KEY> 
       <KEY name="format"> 
        <VALUE>weeks</VALUE> 
       </KEY> 
       <KEY name="showgrades"> 
        <VALUE>1</VALUE> 
       </KEY> 
       <KEY name="lang"> 
        <VALUE></VALUE> 
       </KEY> 
       <KEY name="enablecompletion"> 
        <VALUE>0</VALUE> 
       </KEY> 
      </SINGLE> 
      </MULTIPLE> 
     </RESPONSE> 

私は、このクラスのオブジェクトにこのXMLを解析する:

class Course 
{ 
    public int id { get; set; } 
    public string shortname { get; set; } //short name of course 
    public string fullname { get; set; } //long name of course 
    public int enrolledusercount { get; set; } //Number of enrolled users in this course 
    public string idnumber { get; set; } //id number of course 
    public int visible { get; set; } //1 means visible, 0 means hidden course 
    public string summary { get; set; } 
    public int summaryformat { get; set; } //summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN) 
    public string format { get; set; } //course format: weeks, topics, social, site 
    public int showgrades { get; set; } //true if grades are shown, otherwise false 
    public string lang { get; set; } //forced course language 
    public int enablecompletion { get; set; } //true if completion is enabled, otherwise false 
} 

はそれを行うための直接的な方法があるか、私はパーサを書く必要がありますフィールドごとにスイッチケースを持つ方法?

+1

XMLの代わりにJSON形式のデータを返すのに役立ちますか? parser moodlewsrestformat = jsonをwebserviceリクエストに追加すると、代わりにJSON形式で返されます。 – davosmith

+0

実際に私はJSONも返すことは知っていましたが、何とか忘れてしまい、デフォルトのXMLフォーマットを超えて考えることができませんでした。 JSONの方がはるかに簡単です。ありがとう。 – Danish

答えて

2

XmlReaderを使用してカスタムパーサーを作成する必要があります。プリセットで行うことができるデフォルトのデシリアライザはありません。

また、スイッチ/ケースを使用する必要はありません。反射を使用して小道具を埋めることができます。

+0

ありがとう、私はあまりにも思ったが、私は反射を使用するにはあまりにも怠惰だった:-) – Danish

0

私が知る限り、この構造のデフォルトのデシリアライザはありません。 @Nigrimmistによると、スイッチケースを使う必要はありません。

をxmlの読み取りに使用するか、XmlDocumentで行うことができます。以下の解析用のサンプルコード。私はそれをテストしていないので、注意して使用してください。

public T ConvertFromXml<T>(string yourXml, params object[] activationData) 
    where T : new() //if your type has default constructor 
{ 
    var resultType = typeof(T); 
    //if your type has not default constructor 
    var result = (T)Activator.CreateInstance(typeof(T), activationData); 
    //if it has default constructor 
    var result = new T(); 

    //create an instance of xml reader 
    var xmlDocument = new XmlDocument(); 
    xmlDocument.LoadXml(yourXml); 

    //expecting that your xml response will always have the same structure 
    if (xmlDocument.SelectSingleNode("RESPONSE/SINGLE") != null) 
    { 
     foreach(XmlNode node in xmlDocument.SelectNodes("RESPONSE/SINGLE/KEY")) 
     { 
      var prop = resultType.GetProperty(node.Attributes["name"].Value); 
      if (prop != null) 
      { 
       var value = prop.SelectSingleNode("Value").Value; 
       //if value does not exist - check if null value can be assigned 
       if (value == null && (!prop.PropertyType.IsValueType || (Nullable.GetUnderlyingType(prop.PropertyType) != null))) 
       { 
        prop.SetValue(result, value); //explicitly setting the required value 
       } 
       else if (value != null) 
       { 
        //we receiving the string, so for number parameters we should parse it 
        if (IsNumberType(prop.PropertyType)) 
        { 
         prop.SetValue(result, double.Parse(value)); 
        } 
        else 
        { 
         prop.SetValue(result, value); //will throw an exception if property type is not a string 
        } 

        //need some additional work for DateTime, TimeSpan, arrays and other 
       } 

      } 
      else 
      { 
       //remove next line if you do not need a validation for property presence 
       throw new ArgumentException("Could not find the required property " + node.Attributes["name"].Value); 
      } 
     } 
    } 
    else 
    { 
     throw new ArgumentException("Xml has invalid structure"); 
    } 

    return result; 
} 

private bool IsNumberType(Type t) 
{ 
    var numberTypes = new[] { 
     typeof(byte), typeof(short), typeof(int), typeof(long), 
     typeof(float), typeof(double), typeof(decimal), 
     typeof(byte?), typeof(short?), typeof(int?), typeof(long?), 
     typeof(float?), typeof(double?), typeof(decimal?) 
    }; 

    return numberTypes.Contains(t); 
} 

とサンプルの使用量:

var xml = /*your method to get string representing a xml*/; 
return ConvertFromXml<Course>(xml); 

あなたの代わりにXMLのJSON表現で応答を得ることができる場合、使用するのは簡単ですJson.Netライブラリを見てみましょう。

0

xml linqを使用してください。以下のコードを参照してください。私はidだけを解析しましたが、他のプロパティを追加することができます。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml; 
using System.Xml.Linq; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     const string FILENAME = @"c:\temp\test.xml"; 
     static void Main(string[] args) 
     { 
      Course course = new Course(); 
      course.ReadXML(FILENAME); 
     } 
    } 
    public class Course 
    { 
     public static List<Course> courses = new List<Course>(); 

     public int id { get; set; } 
     public string shortname { get; set; } //short name of course 
     public string fullname { get; set; } //long name of course 
     public int enrolledusercount { get; set; } //Number of enrolled users in this course 
     public string idnumber { get; set; } //id number of course 
     public int visible { get; set; } //1 means visible, 0 means hidden course 
     public string summary { get; set; } 
     public int summaryformat { get; set; } //summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN) 
     public string format { get; set; } //course format: weeks, topics, social, site 
     public int showgrades { get; set; } //true if grades are shown, otherwise false 
     public string lang { get; set; } //forced course language 
     public int enablecompletion { get; set; } //true if completion is enabled, otherwise false 

     public void ReadXML(string filename) 
     { 
      XDocument doc = XDocument.Load(filename); 
      courses = doc.Descendants("SINGLE").Select(x => ReadKeys(x)).ToList(); 
     } 
     public Course ReadKeys(XElement single) 
     { 
      Course newCourse = new Course(); 
      foreach(XElement key in single.Descendants("KEY")) 
      { 
       switch(key.Attribute("name").Value) 
       { 
        case "id" : 
         newCourse.id = (int)key.Element("VALUE"); 
         break; 
       } 
      } 
      return newCourse; 
     } 
    } 
} 
関連する問題