locked
How can I remove header junk and rename inner classes?

    Question

  • Code follows questions.

    Situation: I want simple, bare bones XML to represent a composed class.

    I do not want a header declaration as the OuterClass class will NOT be the root element in the final XML document. This XML has to go through a web service, and the web service XML defines the header and a wrapping root element. I have to be able to put the serialized class inside that service root element.

    I do not want namespace junk.

    I want to rename the element for the contained class.

    Q1: How can I rename InnerClass to (for example) InsideClass when serialized ? I can't use XmlRootAttribute("InsideClass") since this won't be the root of the output, correct?

    Q2: How can I prevent the addition of header junk from .Serialize()?

    Code sample (is compileable):


    using System;
    using System.Xml.Serialization;
    using System.IO;
    using System.Collections;

    public class InnerClass { 
        public string innerString = "inner";
    }
     
    public class OuterClass { 
        public string outerString = "outer"
        public ArrayList theCollection; 
        public OuterClass() { 
            theCollection = new ArrayList(); 
            theCollection.Add(new InnerClass()); 
        }
        public string ToXML() {
            Type[] extraTypes = {typeof(InnerClass)};
            StringWriter writer = new StringWriter();
            XmlSerializer serializer = new XmlSerializer(typeof(OuterClass), extraTypes);
            serializer.Serialize(writer, this);
            writer.Flush();
            return writer.ToString();
        }

    Desired output:
    <OuterClass> 
        <outerString>outer</outerString> 
        <theCollection> 
            <InsideClass> 
                <innerString>inner</innerString> 
            </InsideClass> 
        </theCollection> 
    </OuterClass> 

    What I'm actually getting:
    <?xml version="1.0" encoding="utf-16"?> <!-- can't have this here --> 
    <OuterClass  xmlns:xsi="blahblah" xmlns:xsd="blahblah"<!-- or these attributes --> 
        <outerString>outer</outerString>  
        <theCollection>  
            <anyType xsi:type="InnerClass"<!-- wtf? --> 
                <innerString>inner</innerString>  
            </anyType>  
        </theCollection>  
    </OuterClass>  

    • Edited by allmhuran Monday, October 20, 2008 11:35 PM
    Monday, October 20, 2008 11:08 PM

Answers

  • You may not realize it, but your tone comes across as combative. I thought you should know. I, for instance, am a much nicer person than I'm about to sound.

    I think this may be what you were looking for, more or less:

    <OuterClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
        <outerString>outer</outerString> 
        <theCollection> 
            <InsideClass> 
                <innerString>inner</innerString> 
            </InsideClass> 
            <InsideClass> 
                <innerString>inner</innerString> 
            </InsideClass> 
        </theCollection> 
    </OuterClass> 

    Since your example only included one element in the ArrayList, I can't be sure. Maybe you wanted a single "InsideClass", with many "innerString" elements inside of it.

    This XML does still have the two extra namespace declarations. I don't know how to get rid of those, but they're harmless. If you have code that chokes on those, then it's code that doesn't understand XML. Those two attributes simply declare two namespaces that are not used in the XML that follows.

    The following code generated the above XML:

    public class InnerClass  
    {  
        public string innerString = "inner";  
    }  
     
    public class OuterClass  
    {  
        public string outerString = "outer";  
          
        [XmlArray("theCollection")]  
        [XmlArrayItem("InsideClass")]  
        public List<InnerClass> theCollection;  
          
        public OuterClass()  
        {  
            theCollection = new List<InnerClass> {new InnerClass(), new InnerClass()};  
        }  
          
        public string ToXML()  
        {  
            using (var sw = new StringWriter())  
            {  
                var settings = new XmlWriterSettings {OmitXmlDeclaration = true};  
                using (var writer = XmlWriter.Create(sw, settings))  
                {  
                    var serializer = new XmlSerializer(typeof(OuterClass));  
                    serializer.Serialize(writer, this);  
                }  
                sw.Flush();  
                return sw.ToString();  
            }  
        }  
    }  
     

    Note that this code uses a using statement to ensure that StringWriter.Dispose is called, even if an exception occurs. It also uses a strongly-typed list instead of ArrayList, which should no longer be used.

    You might want to read "Controlling XML Serialization Using Attributes" to learn more.
    John Saunders | Use File->New Project to create Web Service Projects
    • Marked as answer by allmhuran Tuesday, October 21, 2008 2:38 AM
    Tuesday, October 21, 2008 1:12 AM
    Moderator

All replies

  • You may not realize it, but your tone comes across as combative. I thought you should know. I, for instance, am a much nicer person than I'm about to sound.

    I think this may be what you were looking for, more or less:

    <OuterClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
        <outerString>outer</outerString> 
        <theCollection> 
            <InsideClass> 
                <innerString>inner</innerString> 
            </InsideClass> 
            <InsideClass> 
                <innerString>inner</innerString> 
            </InsideClass> 
        </theCollection> 
    </OuterClass> 

    Since your example only included one element in the ArrayList, I can't be sure. Maybe you wanted a single "InsideClass", with many "innerString" elements inside of it.

    This XML does still have the two extra namespace declarations. I don't know how to get rid of those, but they're harmless. If you have code that chokes on those, then it's code that doesn't understand XML. Those two attributes simply declare two namespaces that are not used in the XML that follows.

    The following code generated the above XML:

    public class InnerClass  
    {  
        public string innerString = "inner";  
    }  
     
    public class OuterClass  
    {  
        public string outerString = "outer";  
          
        [XmlArray("theCollection")]  
        [XmlArrayItem("InsideClass")]  
        public List<InnerClass> theCollection;  
          
        public OuterClass()  
        {  
            theCollection = new List<InnerClass> {new InnerClass(), new InnerClass()};  
        }  
          
        public string ToXML()  
        {  
            using (var sw = new StringWriter())  
            {  
                var settings = new XmlWriterSettings {OmitXmlDeclaration = true};  
                using (var writer = XmlWriter.Create(sw, settings))  
                {  
                    var serializer = new XmlSerializer(typeof(OuterClass));  
                    serializer.Serialize(writer, this);  
                }  
                sw.Flush();  
                return sw.ToString();  
            }  
        }  
    }  
     

    Note that this code uses a using statement to ensure that StringWriter.Dispose is called, even if an exception occurs. It also uses a strongly-typed list instead of ArrayList, which should no longer be used.

    You might want to read "Controlling XML Serialization Using Attributes" to learn more.
    John Saunders | Use File->New Project to create Web Service Projects
    • Marked as answer by allmhuran Tuesday, October 21, 2008 2:38 AM
    Tuesday, October 21, 2008 1:12 AM
    Moderator
  • Yep, I just finished adding all that stuff. I managed to strip the namespaces too. They may not cause problems for processing code, but they make the XML harder to eyeball for errors. Plus, since I have no idea what the processing code does, it seems much wiser to be safe than sorry.

    The last thing I need to do is embed that output inside the existing XMLDocument root element. Wrapping it with string constants and issuing a loadXml seems to strip newlines, which I would prefer to preserve. So maybe it would be better to let it get created as a fully formed XmlDocument after all and then copy across via the DOM. Grr, hate the DOM.


    XmlWriterSettings xws new XmlWriterSettings();  
    xws.OmitXmlDeclaration = true
    xws.Indent = true
    xws.IndentChars = "    "

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();  
    ns.Add("","");

    StringBuilder sb = new StringBuilder(); 
    XmlWriter xmlw = XmlWriter.Create(sb, xws);  
    XmlSerializer serializer = new XmlSerializer(this.GetType()); 
    serializer.Serialize(xmlw, this, ns); 
    xmlw.Flush(); 
    return sb.ToString(); 

    Tuesday, October 21, 2008 2:18 AM
  • Fascinating. From http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializernamespaces.aspx:

    Note:

    The creation of an empty namespace and prefix pair is not supported. That is, you cannot create a pair using the following code:

    C#

    Copy Code

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

    ns.Add("", "");

     
    However, it does work.

    You should still use the using statement if you don't want to leak resources.


    John Saunders | Use File->New Project to create Web Service Projects
    • Proposed as answer by mrchief_2000 Wednesday, August 17, 2011 6:59 PM
    • Unproposed as answer by mrchief_2000 Wednesday, August 17, 2011 6:59 PM
    Tuesday, October 21, 2008 2:51 AM
    Moderator
  • Yup, it does indeed.

    The real code is a little more resource friendly, I thought things would be easier to understand if it was stripped down here.
    Tuesday, October 21, 2008 2:53 AM
  • Ok, thanks.

    BTW, people use these forums to find example code. Setting a good example benefits everyone else. In this case, the good example didn't take up much additional space.
    John Saunders | Use File->New Project to create Web Service Projects
    Tuesday, October 21, 2008 2:57 AM
    Moderator