2017-02-02 1 views
0

Ich habe gerungen mit Deserialisieren das folgende XML-Dokument:Handhabung C# XML-Deserialisierung mit Namespaces

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<w:settings xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" mc:Ignorable="w14 w15"> 
    <w:zoom w:percent="100"></w:zoom> 
    <w:proofState w:spelling="clean" w:grammar="clean"></w:proofState> 
    <w:defaultTabStop w:val="720"></w:defaultTabStop> 
    <w:characterSpacingControl w:val="doNotCompress"></w:characterSpacingControl> 
    <w:compat> 
     <w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"></w:compatSetting> 
     <w:compatSetting w:name="overrideTableStyleFontSizeAndJustification" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting> 
     <w:compatSetting w:name="enableOpenTypeFeatures" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting> 
     <w:compatSetting w:name="doNotFlipMirrorIndents" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting> 
     <w:compatSetting w:name="differentiateMultirowTableHeaders" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting> 
    </w:compat> 
    <w:rsids> 
     <w:rsidRoot w:val="00B31FC7"></w:rsidRoot> 
     <w:rsid w:val="00251096"></w:rsid> 
     <w:rsid w:val="00481AA7"></w:rsid> 
     <w:rsid w:val="005C6856"></w:rsid> 
     <w:rsid w:val="00661DE2"></w:rsid> 
     <w:rsid w:val="00984D97"></w:rsid> 
     <w:rsid w:val="00A06ADC"></w:rsid> 
     <w:rsid w:val="00B31FC7"></w:rsid> 
    </w:rsids> 
    <m:mathPr> 
     <m:mathFont m:val="Cambria Math"></m:mathFont> 
     <m:brkBin m:val="before"></m:brkBin> 
     <m:brkBinSub m:val="--"></m:brkBinSub> 
     <m:smallFrac m:val="0"></m:smallFrac> 
     <m:dispDef></m:dispDef> 
     <m:lMargin m:val="0"></m:lMargin> 
     <m:rMargin m:val="0"></m:rMargin> 
     <m:defJc m:val="centerGroup"></m:defJc> 
     <m:wrapIndent m:val="1440"></m:wrapIndent> 
     <m:intLim m:val="subSup"></m:intLim> 
     <m:naryLim m:val="undOvr"></m:naryLim> 
    </m:mathPr> 
    <w:themeFontLang w:val="en-US"></w:themeFontLang> 
    <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink"></w:clrSchemeMapping> 
    <w:shapeDefaults> 
     <o:shapedefaults v:ext="edit" spidmax="1026"></o:shapedefaults> 
     <o:shapelayout v:ext="edit"> 
      <o:idmap v:ext="edit" data="1"></o:idmap> 
     </o:shapelayout> 
    </w:shapeDefaults> 
    <w:decimalSymbol w:val="."></w:decimalSymbol> 
    <w:listSeparator w:val=","></w:listSeparator> 
    <w15:chartTrackingRefBased></w15:chartTrackingRefBased> 
    <w15:docId w15:val="{23720E07-DD19-46BC-8098-ED32713AB32B}"></w15:docId> 
</w:settings> 

Ich bin nur daran interessiert, was im RSIDs Element enthalten ist. Also dachte ich, ich könnte Klassen erstellen, die so aussah:

[XmlRoot(ElementName ="settings", Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")] 
    public class rsids 
    { 
     [XmlElement(ElementName ="rsids",Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")] 
     public List<rsid> Rsids { get; set; } 
    } 

    public class rsid 
    { 
     [XmlAttribute(Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")] 
     public static string val { get; set; } 
    } 

ich so deserialisieren bin versucht:

XDocument xdoc = XDocument.Load(file); 
     using (TextReader reader = new StringReader(xdoc.ToString())) 
     { 
      try 
      { 
       XmlSerializer xmlSerializer = new XmlSerializer(typeof(rsids)); 
       StreamReader sr = new StreamReader(file); 
       rsids SettingsXml = (rsids)xmlSerializer.Deserialize(sr); 

       foreach (var rsid in SettingsXml.Rsids) 
       { 
        Console.WriteLine(rsid.val.Count()); 
       } 

       Console.ReadLine(); 

      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.ToString()); 
       Console.ReadLine(); 
      } 
     } 

Allerdings bin ich die folgende Fehlermeldung erhalten: „Der Wert darf nicht Null sein“. Dies ist mein erster Versuch, ein XML-Dokument mit Namespaces zu deserialisieren. Ich habe die Community durchsucht und viele Artikel von Leuten gefunden, die ähnliche Probleme haben. Nachdem ich einige dieser Lösungen ausprobiert habe, bin ich genauso verwirrt wie zu Beginn und im Kreis. Ich möchte das verstehen. Einige dieser veröffentlichten Lösungen scheinen zu zeigen, dass ich nur ein leeres Namespace-Attribut zu meinen Decorators hinzufügen muss (Namespace = "") und andere zeigen das tatsächliche Namespace-URI, auf das verwiesen wird, aber nur für das root-Element, das Leerzeichen in nachfolgenden Elementen/Attributen hinterlässt . Ich bin mehr auf der Suche nach der Frage "warum", wann eine Methode gegenüber einer anderen zu verwenden und ein Beispiel dafür, wie dies mit dem XML unten erreicht wird. Ich schätze jede Hilfe, die Sie zur Verfügung stellen können.

Prost

Antwort

1

Sie sind aus nicht zu weit.

  1. Ihr XmlElement Attribut impliziert mehrere rsids Elemente. Was Sie wollen, ist ein einzelnes rsids Element, das mehrere rsid Elemente enthält. Der einfachste Weg dazu besteht in der Verwendung der Attribute XmlArray und XmlArrayItem.
  2. Die val Eigenschaft nicht static
  3. Durch sein sollte, was wie a bug in XmlSerializer aussieht, müssen Sie Form = XmlSchemaForm.Qualified in Ihrem XmlAttribute Attribut enthalten.

Sie können auch die meisten Ihrer Namespace Eigenschaften weglassen, wie sie vererbt werden werden, und ElementName muss nicht explizit angegeben werden.

Putting alles zusammen:

[XmlRoot(Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")] 
public class settings 
{ 
    [XmlArray("rsids")] 
    [XmlArrayItem("rsid")] 
    public List<rsid> Rsids { get; set; } 
} 

public class rsid 
{ 
    [XmlAttribute(Form = XmlSchemaForm.Qualified)] 
    public string val { get; set; } 
} 

Natürlich, wenn das ist alles, was Sie wollen, dann eine einfache LINQ to XML-Abfrage viel einfacher wäre:

XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; 

var rsids = doc.Descendants(w + "rsid") 
    .Attributes(w + "val") 
    .Select(x => x.Value); 

Siehe this fiddle für eine funktionierende Demo beider Ansätze.

+0

Danke für die Erklärung. Ich bin näher daran zu verstehen, wie man XML richtig serialisiert. Dein Code hat perfekt funktioniert und die .NET Fiddle ist ziemlich cool. Ich war mir dieser Website nicht bewusst - Danke für Ihre Hilfe. –

0

Versuchen Sie, diese

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) 
     { 
      XDocument doc = XDocument.Load(FILENAME); 

      int[] rsids = doc.Descendants().Where(x => x.Name.LocalName == "rsids").Select(x => new { 
       rsids = x.Elements().Select(y => int.Parse((string)y.Attribute(x.GetNamespaceOfPrefix("w") + "val"), System.Globalization.NumberStyles.HexNumber)) 
      }).Select(x => x.rsids).FirstOrDefault().Select(x => x).ToArray(); 

     } 
    } 

}