C# / XML - Question
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]]></fmstoken_renew>
<adserverXML><![CDATA[http://www.sky.de/dummy.xml]]></adserverXML>
<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</filename>
<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</filename>
<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, t开发者_如何学编程hat 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!
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
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.
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
}
As many people 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;
精彩评论