views:

38

answers:

2

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>
+1  A: 

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

Henk Holterman
How should I edit that statement to include something that checked to see if the attribute was there?
jwaffe
I don't know how to use XDocument or XmlDocument, I just picked the method of reading/writing XML that I knew the best. If you have a good tutorial, I'll take a look. This method does seem cumbersome.
jwaffe
I thought of using that, but it uses a lot of terms I'm not very familiar with (var, foreach, in, from). I guess I could look it up later.
jwaffe
A: 

I don't know exactly what you're trying to accomplish but personally I would create a .NET class representing your class element with properties identifying the sub elements then use System.Xml.Serialization.XmlSerializer to write or read it from a file.

Here is an example:

using System.Xml.Serialization;

public class MyClasses : List<MyClass>{}    

public class MyClass{
 public String Teacher{ get; set; }
}

void main(){
  MyClasses classList = new MyClasses();

  MyClass c = new MyClass();
  c.Teacher = "James";

  classList.Add(c);

  XmlSerializer serializer = new XmlSerializer(classList.GetType());
  serializer.Serialize(/*Put your stream here*/);
}

And, after leaving setting up your stream as an exercise to the reader, blamo, you're done outputing an XML representation of your object to some stream. The stream could be a file, string, whatever. Sorry for nasty C# (if its nasty) I use VB.NET everyday so the syntax and keywords may be a little off.

Update
I added some code to show how to serialize a collection of the classes. If nodes aren't coming out named correctly there are attributes you can add to your class properties, just do a quick google for them.

Update again
Sorry, its hard to explain when we're using the same word to mean two different things. Lets say you're trying to represent a bucket of bricks. You would write a C# class called Brick and a C# class called Bucket that inherited from List<Brick> your Brick would have a property called Color. You would then make all your bricks with different colors and fill the bucket with your bricks. Then you would pass your bucket to the serializer and it would give you something like:

<Bucket>    
  <Brick>  
    <Color>    
      blue     
    </Color>  
  </Brick>   
</Bucket> 

The serializer builds the XML for you from the definitions of your classes so you don't have to worry about the details. You can read more about it here and here

Justin
I'm trying to make several nodes, (each representing a class, i.e., like in school, not the programming class), and each node has elements such as the name of the teacher, room number, etc. I don't see how what you suggested will organize the data into that sort of structure.
jwaffe
You can also create a class representing your list of "classes" (think List<Class>) and fill it with each instance of the class you made to represent your "class" then pass the list to the serializer. It should come out with <classes> being the root object and a bunch of <class> nodes underneath it.
Justin
<Note: terminology>when I say '"class"' I'm referring to something you attend in school. When I say'class' I'm referring the programming class.So you're saying I should make a class that contains all the "classes", and make each "class" an instance of some class? What class? Also, what does a serializer do?
jwaffe
I was just going to add another comment but it was more text than a comment would allow so I just added more to the answer. I think the word class as in class at school was being confused too much with the word class as in a definition of an object in programming.
Justin
Where are you inheriting List <Brick> from? Do we have to define List<Brick>? Is it like an array? I don't quite follow.
jwaffe