Search code examples
xmlreaderxmlwriter

XmlWriter - reading an attribute (quick question)


I'm using this for my code, it outputs to the xml file perfectly, but it adds an ' = ' sign after the element name even though only one of my elements has an attribute.

I suppose I could do something like

if(reader.Getattribute != "")
// I made that up on the spot, I'm not sure if that would really work
{
      Console.WriteLine("<{0} = {1}>", reader.Name, reader.GetAttribute("name"));
}

else
{
      Console.WriteLine("<{0}>", reader.Name);
}

but is there a cleaner way to code that?

My code (without workaround)

using System;
using System.Xml;
using System.IO;
using System.Text;

public class MainClass
{
    private static void Main()
    {
        XmlWriterSettings settings = new XmlWriterSettings();

        settings.Indent = true;


        XmlWriter w = XmlWriter.Create(@"Path\test.xml", settings);



        w.WriteStartDocument();
        w.WriteStartElement("classes");

        w.WriteStartElement("class");
        w.WriteAttributeString("name", "EE 999");
        w.WriteElementString("Class_Name", "Programming");
        w.WriteElementString("Teacher", "James");
        w.WriteElementString("Room_Number", "333");
        w.WriteElementString("ID", "2324324");
        w.WriteEndElement();




        w.WriteEndDocument();
        w.Flush();
        w.Close();




        XmlReader reader = XmlReader.Create(@"Path\test.xml");

        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    Console.WriteLine("<{0} = {1}>", reader.Name, reader.GetAttribute("name"));
                    break;
                case XmlNodeType.Text:
                    Console.WriteLine(reader.Value);
                    break;
                case XmlNodeType.CDATA:
                    Console.WriteLine("<[CDATA[{0}]>", reader.Value);
                    break;
                case XmlNodeType.ProcessingInstruction:
                    Console.WriteLine("<?{0} {1}?>", reader.Name, reader.Value);
                    break;
                case XmlNodeType.Comment:
                    Console.WriteLine("<!--{0}-->", reader.Value);
                    break;
                case XmlNodeType.XmlDeclaration:
                    Console.WriteLine("<?xml version='1.0'?>");
                    break;
                case XmlNodeType.Document:
                    break;
                case XmlNodeType.DocumentType:
                    Console.WriteLine("<!DOCTYPE {0} [{1}]", reader.Name, reader.Value);
                    break;
                case XmlNodeType.EntityReference:
                    Console.WriteLine(reader.Name);
                    break;
                case XmlNodeType.EndElement:
                    Console.WriteLine("</{0}>", reader.Name);
                    break;
            }
        }
    }
}

Output

<?xml version='1.0'?>
<classes = >
<class = EE 999>
<Class_Name = >
Programming
</Class_Name>
<Teacher = >
James
</Teacher>
<Room_Number = >
333
</Room_Number>
<ID = >
2324324
</ID>
</class>
</classes>

Solution

  • Because this line

    case XmlNodeType.Element:
           Console.WriteLine("<{0} = {1}>", reader.Name, reader.GetAttribute("name"));
           break;
    

    Always writes the '=' without checking.

    A rough fix :

    case XmlNodeType.Element:
           Console.WriteLine("<{0}", reader.Name);
           if (reader.HasAttributes)
              // Write out attributes
           Console.WriteLine(">");
           break;
    

    But why are you using the XmlReader at all? It is cumbersome and only useful when dealing with huge Xml streams.

    If your datasets are not >> 10 MB then take a look at XDocument or XmlDocument

    The XmlWriter in your Example can be replaced by (rough approx):

     // using System.Xml.Linq;
    
            var root = new XElement("classes",
                new XElement("class", new XAttribute("name", "EE 999"),
                    new XElement("Class_Name", "Programming"),
                    new XElement("Teacher", "James")
                    ));
    
            root.Save(@"Path\test.xml");
    
         var doc = XDocument.Load(@"Path\test.xml");
         // doc is now an in-memory tree of XElement objects 
         // that you can navigate and query
    

    And here is an intro