4

I'm having issues deserializing the following XML fragment (from OneNote):

<one:OE creationTime="2015-03-21T18:32:38.000Z" lastModifiedTime="2015-03-21T18:32:38.000Z" objectID="{649CA68C-C596-4F89-9885-1553A953529E}{30}{B0}" alignment="left" quickStyleIndex="1" selected="partial">
    <one:List>
        <one:Bullet bullet="2" fontSize="11.0" />
    </one:List>
    <one:T><![CDATA[Bullet point one]]></one:T>
</one:OE>

The following code is used to deserialize the above fragment. The OE class has the following attributes:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34230")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/office/onenote/2013/onenote")]
[System.Xml.Serialization.XmlRootAttribute("OE", Namespace = "http://schemas.microsoft.com/office/onenote/2013/onenote", IsNullable = true)]
public partial class OE : EntityBase<OE>
{
    ...
}

And the actual method to deserialize the fragment is in the base class, EntityBase:

public static T Deserialize(string xml)
{
    System.IO.StringReader stringReader = null;
    try
    {
        stringReader = new System.IO.StringReader(xml);
        return ((T)(Serializer.Deserialize(System.Xml.XmlReader.Create(stringReader))));
    }
    finally
    {
        if ((stringReader != null))
        {
            stringReader.Dispose();
        }
    }
}

The deserialize method is called as follows:

var element = OE.Deserialize(xmlString);

Where the variable xmlString is the XML fragment given above. On calling the Deserialize method, I get the following error:

There is an error in XML document (1,2). ---> System.Xml.XmlException: 'one' is an undeclared prefix. Line 1, position 2.

I have spent some time looking at the attributes declaring the namepaces in the OE class, but everything appears to be correct. Can anyone point out to the mistake I'm making?

Tangiest
  • 43,737
  • 24
  • 82
  • 113
  • 2
    The error tells you the exact problem: the namespace `one` is undefined. I.e. no xmlns attribute exists that initiates `one`. – Der Kommissar Apr 21 '15 at 14:43
  • As the namespace declaration is missing, I assume this is simply chopped out of a larger XML file? Is done programmatically? If so, show this code - it needs changing to be XML-aware. The brute-force chopping out of this element results in invalid XML. – Charles Mager Apr 21 '15 at 15:49

2 Answers2

2

The answer given by matrixanomaly is correct, but unfortunately, the OneNote namespace given is incorrect. I'm working with OneNote 2013 and not 2010. The actual code I used to deserialize the same XML fragment as given in my question is as follows:

public static OE DeserializeFragment(string xmlFragment)
{
    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(OE));
    System.IO.StringReader stringReader = null;
    try
    {
        stringReader = new System.IO.StringReader(xmlFragment);

        NameTable nt = new NameTable();
        XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
        nsManager.AddNamespace("one", "http://schemas.microsoft.com/office/onenote/2013/onenote");
        XmlParserContext context = new XmlParserContext(null, nsManager, null, XmlSpace.None);
        XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
        xmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment;

        return ((OE)(serializer.Deserialize(System.Xml.XmlReader.Create(stringReader, xmlReaderSettings, context))));
    }
    finally
    {
        if ((stringReader != null))
        {
            stringReader.Dispose();
        }
    }
}
Community
  • 1
  • 1
Tangiest
  • 43,737
  • 24
  • 82
  • 113
1

I think you need the original namespace declaration for one. This is because one is a namespace and items like OE and List are prefixes, which exist in the namespace created by oneNote, which the declaration isn't present in the fragment you posted. A prefix exists to avoid collisions in naming in the event that different XML documents get mixed together. see a w3schools link for further explanation

So a workaround would be to append the namespace such as <xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote"> to each fragment (doesn't seem to be the most optimal, but eh it works), and go about deserializing it as you've done.

I don't have OneNote handy so that namespace declaration was from this forum post.

An alternate way of deserializing XML fragments is through XMLReader and XMLReaderSettings, where you can set the coformance level to Fragment. And adding a pre-defined namespace.

Example adapted from this MSDN blog

 XmlDocument doc = new XmlDocument();

        NameTable nt = new NameTable();
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
        nsmgr.AddNamespace("one", "http://schemas.microsoft.com/office/onenote/2010/onenote");
        XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
        XmlReaderSettings xset = new XmlReaderSettings();
        xset.ConformanceLevel = ConformanceLevel.Fragment;
        XmlReader rd = XmlReader.Create(new  StringReader(XMLSource), xset, context); 

        doc.Load(rd);

I personally prefer using XMLReader and XMLReader settings, though they seem like more work having to CreateReader() and set things up, it looks to be a more robust way.

Or, if you don't want to deal with custom namespaces and what not, and don't run into the problem of collisions, just programatically remove the front declaration of one:, and move on with deserializing it. That's more of string manipulation, though.

matrixanomaly
  • 6,627
  • 2
  • 35
  • 58
  • Off topic, but if you wish to set the default namespace for the fragment, just add it's URI to the namespace manager, with a prefix of String.Empty. – GHC Feb 09 '18 at 11:49