2010-08-30 10 views
0

J'ai un problème que j'ai essayé de résoudre depuis presque une semaine maintenant, mais il semble que, malheureusement, je ne peux pas le gérer par moi-même. Peut-être que quelqu'un pourrait m'aider.C#/XML - Question

J'ai ce type de XML source:

<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> 

Et voici les parties du code qui me laisser obligé contenu de la balise de la page XML ci-dessus:

 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]","_"); 

Le problème est :

Tout fonctionne bien sauf le fait qu'il y ait deux balises "filename" et "title" dans le fichier XML source, mais je n'ai besoin de choisir que les secondes, celles qui se trouvent sous cette ligne:

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

et en quelque sorte sauter/ignorer premiers, ceux qui sont au-dessus et à droite ligne précédente sous cette ligne:

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

Je ne peux pas savoir comment faire.

(Ma seule supposition est que cela a peut-être quelque chose à voir avec XPathNavigator, mais je ne suis pas sûr que ce soit une bonne idée, et de toute façon, je ne comprends pas vraiment comment l'utiliser correctement).


Édition: problème résolu. Je tiens à remercier tous ceux qui ont répondu pour vos suggestions. Vraiment apprécié!

+6

Le remplacement d'une expression régulière et d'une chaîne n'est généralement pas la bonne méthode pour modifier un fichier XML. Utilisez une bibliothèque standard, rapide et bien testée à la place. Linq to XML peut aussi faire un peu de magie. Vous tentez une mauvaise réécriture d'une bibliothèque solide créée par des dizaines de professionnels expérimentés (codeurs, testeurs, etc.). –

Répondre

2

Vous devriez vraiment charger le fichier XML en objet XMLDocument puis le modifier. Mais si vous préférez utiliser votre code existant, ce code sale devrait faire l'affaire.

 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); 

Ceci déplacera les index vers la dernière occurrence de la balise que vous recherchez. Remplacez simplement vos déclarations par celles-ci.Edit: En outre, vous utilisez ces quelques lignes faciles à trouver/manipuler votre XML d'une manière beaucoup plus propre.

 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 

Espérons que cela aide.

+0

Merci, merci beaucoup! Ça aide vraiment, ce "code sale" fonctionne comme un charme. Oui, j'ai compris que je devrais travailler avec XML d'une autre manière, mais maintenant je préfère vraiment changer le moins possible, parce que je viens de découvrir une chose dans le code qui doit être corrigé et je dois me concentrer il. Merci encore pour votre aide. –

1

Vous avez besoin cette expression XPath:

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

Ou

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

Ces expression renvoient un ensemble de noeuds avec un élément filename et title dans l'ordre du document.

En C# (je ne suis pas un 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 
} 
6

C'est vraiment pas la bonne façon de s'y prendre pour travailler avec XML en .Net.

Vous n'avez pas mentionné la version de .Net pour laquelle vous développez. Selon la version, utilisez XmlDocument, XDocument/LINQ to XML.

MSDN on LINQ to XML

MSDN on XmlDocument

+3

Tout à fait d'accord. Vous ne pouvez pas exagérer combien de travail vous créez pour vous-même en faisant de cette façon. – tomfanning

1

Comme beaucoup l'ont déjà dit, XPath et LINQ conviennent tous les deux. Voici un exemple LINQ to XML:

 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;