简体   繁体   中英

Parse Malformed XML With Linq

i am trying to parse some xml that i beleve to be malformed using Linq in .net 3.5 , i need to get the data out of the xml and insert the data into variables, i have been using XmlDocument to parse the xml, any examples or assistance is greatly appreciated

XML --

<?xml version="1.0" encoding="UTF-8"?>
<centovacast version="2.2.4" host="my.domain.com">
<response type="success">
<message>Complete</message>
<data><row>
<field name="mount">/stream</field>
<field name="listenercount">0</field>
<field name="genre">Unspecified</field>
<field name="url">http://</field>
<field name="title"></field>
<field name="currentsong">Placebo - One Of A Kind</field>
<field name="bitrate">128</field>
<field name="sourceconnected">1</field>
<field name="serverstate">1</field>
<field name="sourcestate">1</field>
<field name="reseller">0</field>
<field name="ipaddress"></field>
<field name="port">13282</field>
<field name="proxy">0</field>
<field name="servertype">ShoutCast</field>
<field name="sourcetype">icescc</field>
</row><row><field></field></row></data></response></centovacast>

another problem is that sometimes the "currentsong" value may contain special characters, such as ! , % , ^ & etc and i know that can sometimes cause issues with xml.

-- Code i'm trying to use to parse the XML

        XElement xml = XElement.Parse(data);

        var query = from p in xml.Elements("name")
                    select p;

        foreach (var record in query)
        {
            MessageBox.Show(String.Format("Info: {0} {1}",
                                                record.Element("url"),
                                                record.Element("title")));
        }

Your LINQ is wrong. You are looking for an element called name . You don't have one. You have elements called field .

ETA: OK, I am redoing this now that I have a better look at your XML.

  var query = from r in xml.Elements("row") 
                select r; 

You also need to look at the Attributes collection, because that's what name is: an attribute. The following is from memory, but it would look something like this:

foreach(XElement row in query)
{
    var urlElement = row.Elements("field").Single(qe=>qe.HasAttributes && qe.Attribute("name").Value == "url");
    var titleElement = row.Elements("field").Single(qe => qe.HasAttributes && qe.Attribute("name").Value == "title");
    MessageBox.Show(String.Format("Info: {0} {1}", urlElement.Value, titleElement.Value));
}

Linq2Xml code below works with your xml.

var xDoc = XDocument.Parse(xml); //XDocument.Load(filename)

var dict = xDoc.Descendants("field")
               .Where(e=>e.HasAttributes)
               .ToDictionary(e => e.Attribute("name").Value, e => e.Value);

Console.WriteLine(dict["currentsong"]);

The following code will parse the XML in the way that you seem to want. Note that you will probably have problems with XElement throwing an exception loading your XML if is has any of the special characters in it. You may want to pre-process the string to escape those characters properly before you try to parse it. Note also that it doesn't like the second row element with the empty field element. If you expect to get things like that from your source, you'll have to write some error handling to either find it or catch the exception and dump the whole row.

The XML provided isn't badly formed, but it is rather odd - the name of each field ought to be the name of the element, not an attribute to it. This makes parsing it a little trickier. This uses Descendents to skip past the other elements and get all of the row elements in the file directly. The Linq First method is then used to find the element with the attribute value that you want and get the element value from it.

var query = from p in xml.Descendants("row")
                    select p;

foreach (var record in query)
{
    MessageBox.Show(String.Format("Info: {0} {1}",
        record.Elements().First(e => e.Attribute("name").Value.Equals("url")).Value,
        record.Elements().First(e => e.Attribute("name").Value.Equals("title")).Value));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM