tags:

views:

113

answers:

4

Hello everybody.

I’ve got a problem witch I’ve been trying to solve almost for a week now, but it seems that, unfortunately, I can’t manage it by myself. Maybe somebody could help me.

I’ve got this type of source XML:

<data> 
<para1>24499</para1> 
<para2>32080148</para2> 
<para4>20e500cc6008d0f8ab1fd108b220ca261f85edd9</para4> 
<para6></para6> 
<timetype>4</timetype> 
<fkcontent>964342</fkcontent> 
<season>0</season> 
<fmstoken><![CDATA[7bca3c544ad64e526806fb5a6b845148]]></fmstoken> 
<fmstoken_user>32010484</fmstoken_user> 
<fmstoken_time>1283165972</fmstoken_time> 
<fmstoken_renew><![CDATA[http://www.sky.com/logic/fmstoken.php?method=refresh]]&gt;&lt;/fmstoken_renew&gt; 
<adserverXML><![CDATA[http://www.sky.de/dummy.xml]]&gt;&lt;/adserverXML&gt; 
    <playlist> 
<videoinfo quality="0" name="DSL 1000"> 
    <id>24499</id> 
    <noad>1</noad> 
    <productplacement>0</productplacement> 
    <filename>http://www.sky.com/video/1/V_53511_BB00_E81016_46324_16x9-lq-512x288-vp6-c0_bbb491b3ce64ef667340a21e2bfb3594.f4v&lt;/filename&gt; 
    <title><![CDATA[Who will be the winner?]]></title> 

    </videoinfo> 
<videoinfo quality="1" name="DSL 2000"> 
    <id>24499</id> 
    <noad>1</noad> 
    <productplacement>0</productplacement> 
    <filename>http://www.sky.de/video/1/V_53513_BB00_E81016_46324_16x9-hq-512x288-vp6-c0_fa948bc5429cf28455779666cc59cf5e.f4v&lt;/filename&gt; 
    <title><![CDATA[Who will be the winner?]]></title> 

    </videoinfo> 
    </playlist> 
</data>

And here are parts of the code that let me get required tag content from xml page above:

        private static string getTagContent(string source, string tag)
    {
        string fullTagBegin = "<" + tag + ">";
        string fullTagEnd = "</" + tag + ">";

        int indexBegin = source.IndexOf(fullTagBegin) + fullTagBegin.Length;
        int indexEnd = source.IndexOf(fullTagEnd);
        int indexLength = indexEnd - indexBegin;

        if (indexBegin == -1 || indexEnd == -1)
            return "UNKNOWN";
        return source.Substring(indexBegin, indexLength);
    }



    public static void Start(String url)
    {
        try
        {
            String urlXML = url;
            WebClient wClient = new WebClient();

            string sourceXML = wClient.DownloadString(urlXML);
            sourceXML = sourceXML.Replace("]]>", "");
            sourceXML = sourceXML.Replace("<![CDATA[", "");


            String para1 = getTagContent(sourceXML, "para1");
            String para2 = getTagContent(sourceXML, "para2");
            String para4 = getTagContent(sourceXML, "para4");
            String timetype = getTagContent(sourceXML, "timetype");
            String fkcontent = getTagContent(sourceXML, "fkcontent");
            String season = getTagContent(sourceXML, "season");
            String fmstoken = getTagContent(sourceXML, "fmstoken");
            String fmstoken_user = getTagContent(sourceXML, "fmstoken_user");
            String fmstoken_time = getTagContent(sourceXML, "fmstoken_time");
            String fmstoken_renew = getTagContent(sourceXML, "fmstoken_renew");
            String filename = getTagContent(sourceXML, "filename").Replace("http://", "");
            String title = System.Text.RegularExpressions.Regex.Replace(getTagContent(sourceXML, "title"), @"[^a-zA-Z0-9]","_");

The problem is:

everything works fine except the fact, that there are two "filename" and "title" tags in the source xml, but I need to choose only second ones, those that are under this line:

<videoinfo quality="1" name="DSL 2000">,

and somehow skip/ignore first ones, those that are above previous line and right under this line:

<videoinfo quality="0" name="DSL 1000">

I can't figure out how to do that.

(My only guess is that maybe it has something to do with XPathNavigator, but I’m not sure if that’s a right guess, and anyway, I don’t really understand how to use it properly).


Edit: problem solved. I want to thank everyone who replied for your suggestions. Really appreciated!

+1  A: 

You need this XPath expression:

/data/playlist/videoinfo[2]/filename | /data/playlist/videoinfo[2]/title

Or

/data/playlist/videoinfo[2]/*[self::filename or self::title]

These expression return a node set with filename and title element in document order.

In C# (I'm not an expert):

XPathDocument doc = new XPathDocument("document.xml"); 

XPathNodeIterator nodeset = doc.CreateNavigator() 
    .Select("/data/playlist/videoinfo[2]/*[self::filename or self::title]"); 

foreach (XPathNavigator node in nodeset) 
{ 
// Your code 
} 
Alejandro
+5  A: 

This is really not the right way to go about working with XML in .Net.

You didn't mention which version of .Net you are developing for. Depending on the version look into using XmlDocument, XDocument / LINQ to XML.

MSDN on LINQ to XML

MSDN on XmlDocument

Arkain
Absolutely agree. Cannot overstate how much work you're creating for yourself by doing it this way.
tomfanning
+1  A: 

You should really load the XML into XMlDocument object and then edit it. But if you prefer to use your existing code, this dirty code should do the trick.

        int indexBegin = source.IndexOf(fullTagBegin) == source.LastIndexOf(fullTagBegin) ? source.IndexOf(fullTagBegin) + fullTagBegin.Length : source.LastIndexOf(fullTagBegin) + fullTagBegin.Length;
        int indexEnd = source.IndexOf(fullTagEnd) == source.LastIndexOf(fullTagEnd) ? source.IndexOf(fullTagEnd) : source.LastIndexOf(fullTagEnd);

This will move the indexes to the last occurrence of whatever tag you're looking for. Just replace your declarations with this ones.

Edit: Additionally, you use this easy few lines to find/manipulate your XML in a much cleaner way.

        XmlDocument doc = new XmlDocument();
        doc.Load(filename);
        // or doc.LoadXML(fullXMLcode);

        var elements = doc.GetElementsByTagName("title");
        var element = elements.Item(elements.Count - 1); // returns the last element
        // element.InnerText gets the value you need. You can use this property to change it, too

Hope this helps.

Tomislav Markovski
Thank you, thank you so much! It really helps, this “dirty code” works like a charm.Yes, I got that I should work with XML another way, but right now I really prefer to change as little as possible, because I’ve just discovered one more thing in the code that must be fixed and I have to concentrate on it.Thanks again for your help.
Amy Joyce
+1  A: 

As many have already said, XPath and LINQ are both suitable. Here's LINQ to XML sample:

        XDocument doc = XDocument.Load("yourXml.xml");

        var result =
        (from videoInfo in doc.Descendants("videoinfo")
        let quality = videoInfo.Attribute("quality")
        let name = videoInfo.Attribute("name")
        where (quality != null && quality.Value == "1")
                && (name != null && name.Value == "DSL 2000")
        select new 
            {
                Title = videoInfo.Element("title"),
                FileName = videoInfo.Element("filename")
            }
        ).First();

        string title = result.Title.Value;
        string fileName = result.FileName.Value;
Dmitry Ornatsky