0

I have been wrestling with deserializing the following XML document:

    <?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>

I am only interested in what is contained within the rsids element. So I thought I could create classes that looked like this:

 [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; }
    }

I am attempting to deserialize like this:

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();
            }
        }

However, I am getting the following error: "Value cannot be null". This is my first attempt at deserializing an XML document with Namespaces. I have browsed the community and found plenty of articles of folks having similar issues however, after trying some of those solutions I am just as confused as when I started and just going in circles. I want to understand this. Some of those posted solutions out there seem to indicate I only have to add a blank Namespace attribute to my decorators (Namespace ="") and others show the actual namespace uri being referenced but only for the root element leaving blanks in subsequent elements \ attributes. I am more looking for the education as to 'why'\'when' to use one method over another and an example of how to accomplish this given the XML below. I appreciate any help you can provide.

Cheers

2 Answers 2

1

You're not too far off.

  1. Your XmlElement attribute implies multiple rsids elements. What you want is a single rsids element containing multiple rsid elements. The easiest way to do this is using the XmlArray and XmlArrayItem attributes.
  2. The val property shouldn't be static
  3. Due to what looks like a bug in XmlSerializer, you need to include Form = XmlSchemaForm.Qualified in your XmlAttribute attribute.

You can also omit most of your Namespace properties as they'll be inherited, and ElementName doesn't have to be specified explicitly.

Putting all that together:

[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; }
}

Of course, if that's all you want then a simple LINQ to XML query would be a lot easier:

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

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

See this fiddle for a working demo of both approaches.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the explanation. I am closer to understanding how to properly serialize XML. Your code worked perfectly and the .NET Fiddle is pretty cool. I wasn't aware of this website - Thanks for your help.
0

Try this

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();

        }
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.