Laden...

XML Deserialisieren, aber nur Teile davon

Erstellt von musicones vor 9 Jahren Letzter Beitrag vor 9 Jahren 1.738 Views
M
musicones Themenstarter:in
28 Beiträge seit 2006
vor 9 Jahren
XML Deserialisieren, aber nur Teile davon

Hallo,

ich arbeite gerade an der Implementation einiger Web-Apis, die mir auf Anfrage XML zurückliefern. Ich möchte die Antwort dann in Objekte bzw. Objektliste deserialisieren.

Ich habe dies bereits anhand einer API erfolgreich durchexerziert. Bei der aktuellen API stolpere ich aber, da die Liste mit den relevanten Daten nicht sofort anfängt, sondern erst einige Tags später in der XML, bzw. diese einfach verschachtelter aufgebaut ist.

Meine Frage deshalb, wie kann ich beim Deserialisieren angeben, dass der Root zwar X heisst, die benötigten Daten aber in der Struktur ab Y zu finden sind.

Um ein genaues Bild wiedergeben zu können, habe ich ein kleines Testprogramm mit zwei XML-Dateien angehangen. Die eine funktioniert, die andere nicht.
Ziel ist es auch die nicht funktionierende einlesen zu können.

Zur Info. das Testprogramm ist geschrieben in und mit : #Develop 5 mit C# 5 und .Net-Framework 4.5.2

Funktioniert:


<response>
  <result first="Value 1" second="5" third="122"/>
  <result first="Value 2" second="9" third="13"/>
  <result first="Value 3" second="12" third="4"/>
</response>

Funktioniert nicht.


<response>
  <method>something here</method>
  <answer>
    <result first="Value 1" second="5" third="122"/>
    <result first="Value 2" second="9" third="13"/>
    <result first="Value 3" second="12" third="4"/>
  </answer>
</response>

Wenn ihr das Programm nicht runterladen möchtet, kann ich den Code auch hier posten, dachte nur es wäre nicht so übersichtlich.

Danke und Gruß

M
19 Beiträge seit 2014
vor 9 Jahren

Meiner Meinung nach geht das nicht in einem Schritt. Du willst dem Deserialisierer als Parameter mitgeben, wo er anfangen soll. Richtig?

Das wird wohl nix. Du musst Dich mit einem XmlReader durchtasten bis zu der Ebene, von der aus Du verarbeiten willst. Und musst noch abfragen, wann sie zu Ende ist.

Das Problem kenn ich gut von XML-Dateien, die SAP exportiert. Da muss man auch zu Fuß immer zu <item> runter ...

M
musicones Themenstarter:in
28 Beiträge seit 2006
vor 9 Jahren

Also die XML selbst parsen empfinde ich als Unsinn, angesichts einer Technik, die das für mich macht. Ich habe aber das Gefühl, diese Technik nicht zur Gänze verstanden zu haben und Möglichkeiten zu übersehen, die es meines Verständnisses nach aber geben müsste.

Grundsätzlich habe ich es jetzt aber ersteinmal, durch Ummodellierung der Klassen etc. die ganze XML zu deserialisieren. Ich kann mich also vom Hauptobjekt auf die Liste stürzen. Technisch wäre das Problem damit grundsätzlich teilgelöst.

Die einzelnen Listenelemente:


  [System.Xml.Serialization.XmlTypeAttribute( AnonymousType = true )]  
  public partial class responseResult 
  {
    #region PUBLIC FIELDS

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string first { get; set; }
 
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte second { get; set; }
 
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte third { get; set; }

    public override string ToString()
    {
      return String.Format("{0}<{1}> : {2}",first, second, third);
    }
    
    #endregion   
  }

Die Liste:

  
  [System.Xml.Serialization.XmlTypeAttribute( AnonymousType = true )]
  [System.Xml.Serialization.XmlRootAttribute( Namespace = "", IsNullable = false )]
  public partial class response 
  {
    public response()
    {
     answer = new List<responseResult>();
    }
    
    #region PUBLIC FIELDS
    
    public string method { get; set; }
    
    [System.Xml.Serialization.XmlArrayItemAttribute( "result", IsNullable = false )]
    public List<responseResult> answer { get; set; }
             
    #endregion
    
    public void AddResult(string first, byte second, byte third)
    {
      responseResult Item = new responseResult();
      Item.first = first;
      Item.second = second;
      Item.third = third;
      
      answer.Add(Item);
    }
  }

Das Oberobjekt:

  
  public class TestDes
  {
    public response MyResponse {get; set;}
    public string RootElement {get; set; }
      
    public TestDes()
    {
     MyResponse = new response();
    }
   
    public void DeserializeFromFile(string Filename)
    {		  
      XmlRootAttribute rootNode = new XmlRootAttribute();
      rootNode.ElementName = RootElement;
      rootNode.IsNullable = true;
      
      XmlSerializer deserializer = new XmlSerializer(typeof(response), rootNode);
      StreamReader stream = new StreamReader(Filename, System.Text.Encoding.Default);
      
       
      MyResponse = (response)deserializer.Deserialize(stream);
      
      stream.Close();  
    }	       

    public string SerializeToStr() 
    {
      XmlRootAttribute rootNode = new XmlRootAttribute();
      rootNode.ElementName = RootElement;
      rootNode.IsNullable = true;
      rootNode.Namespace = String.Empty;
      XmlSerializer serializer = new XmlSerializer(typeof(response), rootNode);
      
      XmlWriterSettings settings = new XmlWriterSettings();    
      settings.Indent = true;
      settings.OmitXmlDeclaration = true;
      
      using (StringWriter textWriter = new StringWriter())
      {
        using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
        {
            serializer.Serialize(xmlWriter, MyResponse);
        }
        
        return textWriter.ToString();
      } 
    }  

    
    public override string ToString()
    {
      string result = "List is empty";
    
      if (MyResponse.answer.Count > 0)
      {
        result = String.Empty;
        
    	  foreach (responseResult Item in MyResponse.answer) 
    	  {
    	    result += Item.ToString() + Environment.NewLine;
    	  }
      }
    
      return result;
    } 
  }

Die Kür wäre, wenn man jetzt noch die Struktur so vereinfachen könnte,
dass ich nicht von MyObject.response.answer, sondern direkt über MyObject.answer
auf die Liste zugreifen könnte.

16.807 Beiträge seit 2008
vor 9 Jahren

Diese von Dir genannte Technik ist aber nicht perfekt und auch nicht für alle Fälle anwendbar.
Vor allem Flexibilität und Geschwindigkeit stehen hier in Konkurrenz zu Komfort.