none
Read attribute's value in an XML string

    Question

  • Hello all,
    I have to retreive xml node's attribute from a string which is of the following form:

    <File name='filename'>CONTENTES HERE</File>

    Actually I have two methods;
    First methods takes a file from a directory and converts it into bytes[]. This byte[] is converted to string to be sent to a methods which again converts in bytes[] and this byte[] written on disk to create the file again. I am using FileStream for the purpose of reading and writing file.
    Here is my first method:

     public string ReadFile(string URL,string File_Name)
            {
                #region   
                string XMLdata = "";
                string imageString="";
                string path = Path.Combine(URL, File_Name);           
                byte[] imageBytes;
                if (File.Exists(path))
                {
                    FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                    imageBytes = new byte[fs.Length];
                    fs.Read(imageBytes, 0, imageBytes.Length);
                    fs.Close();
                    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                    imageString = "<File name='" + File_Name + "'>";

                    imageString = System.Text.ASCIIEncoding.Default.GetString(imageBytes,0,imageBytes.Length);// encoding.GetString(imageBytes, 0, imageBytes.Length);
                    imageString = imageString + "</File>";
                   

                }
                return imageString;
                #endregion
            }


    The following method takes the above string, converts it in bytes[] and writes in on the disk using FileStream.

    public string WriteFile(string URL, string Serializedstr)
            {
                #region
                string StrSerialized = Serializedstr;
                byte[] imageBytes;
                string attribute = "";

                StreamWriter writer = new StreamWriter("file.xml");
                writer.WriteLine(StrSerialized);
                writer.Close();

                TextReader reader = new StreamReader("file.xml");
                string image_String = reader.ReadToEnd();
               

                System.Xml.XmlReader XR = new System.Xml.XmlTextReader(reader);reader.Close();

                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(StrSerialized);
                attribute = xmldoc.NextSibling.Attributes["name"].Value;

                System.Text.ASCIIEncoding encoding = new ASCIIEncoding();

                imageBytes = System.Text.ASCIIEncoding.Default.GetBytes(StrSerialized);// encoding.GetBytes(StrSerialized);
                FileStream fs2 = new FileStream(URL + "myimage2.bmp", FileMode.CreateNew);
                fs2.Write(imageBytes, 0, imageBytes.Length);
                fs2.Close();
                return attribute;
                #endregion
            }

    The only problem is that i am not able to read the xml tag "<File name='" + File_Name + "'>"CONTENTS"</File>" and get the name attribue of File tag.
    This is the work of some xml class but i have no idea of working with xml and reading the attributes of tags as above.
    Please help me finish this task.
    Thanks in advance
    Wednesday, December 05, 2007 6:34 AM

Answers

  • I prefer to use XmlSerializer class to handle this kind of reading and writing of Xml. In this perticular case, I would declare class, say MyFileClass:

    Code Block

    [XmlRoot("File")]

    public class MyFileClass

    {

    private string _fileName;

    [XmlAttribute("filename")]

    public string FileName

    {

    get { return _fileName; }

    set { _fileName = value; }

    }

     

    private byte[] _fileContent;

    [XmlText]

    public byte[] FileContent

    {

    get { return _fileContent; }

    set { _fileContent = value; }

    }

    }

     

    The code I used to test:

    Code Block

    [TestMethod]

    public void ReadWriteBinary()

    {

    MyFileClass myfile = new MyFileClass();

    myfile.FileName = "file.bin";

    myfile.FileContent = new byte[256];

     

    for (int i = 0; i < 256; i++)

    {

    myfile.FileContent[i] = (byte)i;

    }

     

    XmlSerializer s = new XmlSerializer(typeof(MyFileClass));

    StringWriter strw = new StringWriter();

    s.Serialize(strw, myfile);

    strw.Close();

    string str = strw.ToString();

    StringReader reader = new StringReader(str);

    myfile = (MyFileClass)s.Deserialize(reader);

    reader.Close();

    }

     

     

    and the Xml it produces:

    Code Block

    <?xml version="1.0" encoding="utf-16"?>

    <File xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" filename="file.bin">AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==</File>

     

     

    Thursday, December 06, 2007 5:18 PM

All replies

  • First off, unless you really know what you're doing, you should never formulate XML with string manipulation.  Most code that generates XML via string manipulation is unreliable, and yours is no exception:  it will produce XML that can't be parsed if (for instance) it ever encounters a filename that contains an ampersand.

     

    You also can't use ASCIIEncoding to encode binary data as XML text content.  Well, you can, but it will eventually fail.  Not every ASCII character is legal in an XML document, and sooner or later the binary data you're encoding will include one of those characters. 

     

    You want to use Base64 encoding instead.  By a happy coincidence (actually, it's not a coincidence at all), XmlWriter and XmlReader give you methods for doing this.

     

    You should be writing to an XmlWriter in your ReadFile method:

     

    Code Block

       // code that builds imageBytes[] goes here

       xw.WriteStartElement("File");

       xw.WriteAttributeString("name", filename);

       xw.WriteAttributeString("size", imageBytes.Length);

       xw.WriteBase64Text(imageBytes, 0, imageBytes.Length);

       xw.WriteEndElement();

     

     

     

    The corresponding code to read the data from an XmlReader is:

     

    Code Block

       while (xr.Read())

       {

          if (xr.NodeType = XmlNodeType.Element && xr.Name == "File")

          {

             filename = xr.GetAttribute("filename");

             int length = Convert.ToInt(xr.GetAttribute("length"));

             xr.MoveToContent();

             byte[] imageBytes = new byte[length];

             xr.ReadContentAsBase64(imageBytes, 0, length);

             // do something with imageBytes here

          }

       }

     

     

    Wednesday, December 05, 2007 8:57 PM
  • If this is your only problem here's some quick code to give you what you need. If you need to change the XPATH (that's the "//File/@name" part) you can take a look at W3Schools for a tutorial.

     
    Code Block

            string ReadFileName(string xml)
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xml);

                XmlNode node = xmlDoc.SelectSingleNode("//File/@name");
                if (null == node)
                    return string.Empty;
                else
                    return node.Value;
            }


    Wednesday, December 05, 2007 8:57 PM
  • I prefer to use XmlSerializer class to handle this kind of reading and writing of Xml. In this perticular case, I would declare class, say MyFileClass:

    Code Block

    [XmlRoot("File")]

    public class MyFileClass

    {

    private string _fileName;

    [XmlAttribute("filename")]

    public string FileName

    {

    get { return _fileName; }

    set { _fileName = value; }

    }

     

    private byte[] _fileContent;

    [XmlText]

    public byte[] FileContent

    {

    get { return _fileContent; }

    set { _fileContent = value; }

    }

    }

     

    The code I used to test:

    Code Block

    [TestMethod]

    public void ReadWriteBinary()

    {

    MyFileClass myfile = new MyFileClass();

    myfile.FileName = "file.bin";

    myfile.FileContent = new byte[256];

     

    for (int i = 0; i < 256; i++)

    {

    myfile.FileContent[i] = (byte)i;

    }

     

    XmlSerializer s = new XmlSerializer(typeof(MyFileClass));

    StringWriter strw = new StringWriter();

    s.Serialize(strw, myfile);

    strw.Close();

    string str = strw.ToString();

    StringReader reader = new StringReader(str);

    myfile = (MyFileClass)s.Deserialize(reader);

    reader.Close();

    }

     

     

    and the Xml it produces:

    Code Block

    <?xml version="1.0" encoding="utf-16"?>

    <File xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" filename="file.bin">AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==</File>

     

     

    Thursday, December 06, 2007 5:18 PM