2016-09-20 2 views
1

XML Exemple:
Aplatir XDocument complexe sans le savoir DOM

<Pricing> 
    <PriceGuide id="e4c3db5c"> 
    <Name>Price Guide A</Name> 
    <Products> 
     <Product id="1"> 
     <Name>Product 1</Name> 
     <Prices> 
      <Price> 
      <Region id="40">Chicago</Region> 
      <PriceLow>48</PriceLow> 
      <PriceHigh>52</PriceHigh> 
      <UnitOfMeasure>MT</UnitOfMeasure> 
      </Price> 
      <Price> 
      <Region id="71">Dallas</Region> 
      <PriceLow>45.5</PriceLow> 
      <PriceHigh>47</PriceHigh> 
      <UnitOfMeasure>MT</UnitOfMeasure> 
      </Price> 
     </Prices> 
     </Product> 
     <Product id="2"> 
     <Name>Product 2</Name> 
     <Prices> 
      <Price> 
      <Region id="40">Chicago</Region> 
      <PriceLow>48</PriceLow> 
      <PriceHigh>49</PriceHigh> 
      <UnitOfMeasure>MT</UnitOfMeasure> 
      </Price> 
      <Price> 
      <Region id="101">Los Angeles </Region> 
      <PriceLow>43</PriceLow> 
      <PriceHigh>45</PriceHigh> 
      <UnitOfMeasure>MT</UnitOfMeasure> 
      </Price> 
      <Price> 
      <Region id="71">Dallas</Region> 
      <PriceLow>45.5</PriceLow> 
      <PriceHigh>48.5</PriceHigh> 
      <UnitOfMeasure>MT</UnitOfMeasure> 
      </Price> 
     </Prices> 
     </Product> 
    </Products> 
    </PriceGuide> 
</Pricing> 



Résultat attendu: (les données écrites dans un fichier CSV ou jetés dans un DataTable)

Price Guide A, Product 1, Chicago, 48, 52, MT 
Price Guide A, Product 1, Dallas, 45.5, 47, MT 
Price Guide A, Product 2, Chicago, 48, 49, MT 
Price Guide A, Product 2, Los Angeles, 43, 45, MT 
Price Guide A, Product 2, Dallas, 45.5, 48.5, MT 



Problème principal:
Je reçois essentiellement un fichier XML inconnu que je dois montrer comme une table plate.

Ceci est un exemple de l'un des nombreux fichiers que je pourrais avoir à traiter. Je ne connais pas le DOM à l'avance, donc je ne peux pas faire une requête LINQ droite avec des noms de nœuds donnés. J'ai essayé de marcher sur le DOM de manière recusive, mais quand vous êtes dans la récursion, il est difficile de savoir quand il est temps d'écrire un disque.

Extra Credit:
Dans l'exemple, il y a parfois des attributs sur un nœud. S'il y a l'attribut "id", je voudrais inclure la valeur pour cela dans la sortie. Dans ce cas, ma sortie serait:

e4c3db5c, Price Guide A, 1, Product 1, 40, Chicago, 48, 52, MT 
e4c3db5c, Price Guide A, 1, Product 1, 71, Dallas, 45.5, 47, MT 
e4c3db5c, Price Guide A, 2, Product 2, 40, Chicago, 48, 49, MT 
e4c3db5c, Price Guide A, 2, Product 2, 101, Los Angeles, 43, 45, MT 
e4c3db5c, Price Guide A, 2, Product 2, 71, Dallas, 45.5, 48.5, MT 



Merci à l'avance.

Edit:
Les travaux suivants, mais exige de moi de savoir à l'avance la structure XML. Je cherche à généraliser ce code:

var details = 
from level1 in _xmlDoc.Root.Elements("PriceGuide") 
from level2 in level1.Elements("Name") 
from level3 in level2.Elements("Products") 
from level4 in level3.Elements("Product") 
from level5 in level4.Elements("Name") 
from level6 in level5.Elements("Prices") 
from level7 in level6.Elements("Price") 
from level8a in level7.Elements("Region") 
from level8b in level7.Elements("PriceLow") 
from level8c in level7.Elements("PriceHigh") 
from level8d in level7.Elements("UnitOfMeasure") 
select new 
{ 
       PriceGuideId = (string)level1.Attribute("id"), 
       PriceGuideName = (string)level2.Value, 
       ProductId = (string)level3.Attribute("id"), 
       ProductName = (string)level4.Value, 
       RegionId = (string)level8a.Attribute("id"), 
       RegionName = (string)level8a.Value, 
       PriceLow = (string)level8b.Value, 
       PriceHigh = (string)level8c.Value, 
       UnitOfMeasure = (string)level8d.Value, 
}; 

Je sais que cela n'aide pas beaucoup.

+0

Si vous ne connaissez pas le DOM, comment savez-vous quelles données doivent être extraites? – Jules

+0

Fondamentalement les valeurs de chaque noeud dans la hiérarchie. (Avec la valeur de l'attribut "id" jeté si possible). Je ne verrais pas d'inconvénient à des valeurs vides pour les nœuds du XML qui ont des nœuds enfants, mais pas à des valeurs si cela facilite le codage. – Rumtis

+0

J'ai ajouté ce qui fonctionne si je code en dur les noms de nœuds, mais j'ai besoin d'un moyen de généraliser le code. – Rumtis

Répondre

0

Je ne sais pas comment le faire en linq. Voici un code rapide et sale qui fonctionne

XmlDocument dom = new XmlDocument(); 
    dom.LoadXml("<Pricing><PriceGuide id=\"e4c3db5c\"><Name>Price Guide A</Name><Products><Product id=\"1\"><Name>Product 1</Name><Prices><Price><Region id=\"40\">Chicago</Region><PriceLow>48</PriceLow><PriceHigh>52</PriceHigh><UnitOfMeasure>MT</UnitOfMeasure></Price><Price><Region id=\"71\">Dallas</Region><PriceLow>45.5</PriceLow><PriceHigh>47</PriceHigh><UnitOfMeasure>MT</UnitOfMeasure></Price></Prices></Product><Product id=\"2\"><Name>Product 2</Name><Prices><Price><Region id=\"40\">Chicago</Region><PriceLow>48</PriceLow><PriceHigh>49</PriceHigh><UnitOfMeasure>MT</UnitOfMeasure></Price><Price><Region id=\"101\">Los Angeles </Region><PriceLow>43</PriceLow><PriceHigh>45</PriceHigh><UnitOfMeasure>MT</UnitOfMeasure></Price><Price><Region id=\"71\">Dallas</Region><PriceLow>45.5</PriceLow><PriceHigh>48.5</PriceHigh><UnitOfMeasure>MT</UnitOfMeasure></Price></Prices></Product></Products></PriceGuide></Pricing>"); 

    List<KeyValuePair<int, String>> result = FlattenXML(dom.DocumentElement, "", 0); 
    var q = result.Where(c => c.Key == result.Max(b => b.Key)).Select(b => b.Value.Substring(0, b.Value.Length - 1)).ToArray(); 

    Console.WriteLine(String.Join(System.Environment.NewLine, q)); 

    private List<KeyValuePair<int, String>> FlattenXML(XmlElement node, String parent, int level) 
    { 
     List<KeyValuePair<int, String>> result = new List<KeyValuePair<int, String>>(); 
     String detail = ""; 

     if (node.HasAttribute("id")) 
      parent += node.Attributes["id"].InnerText + ","; 

     if (node.InnerText == node.InnerXml && node.InnerText != "") 
     { 
      parent += node.InnerText + ","; 
     } 

     foreach (XmlElement child in node.ChildNodes) 
     { 
      if (child.InnerText == child.InnerXml && child.InnerText != "") 
      { 
       detail += child.InnerText + ","; 
       level++; 
      } 

      if (child.FirstChild != child.LastChild) 
      { 
       List<KeyValuePair<int, String>> childResult = FlattenXML(child, parent + detail, level); 
       result.AddRange(childResult); 
      } 
     } 
     result.Add(new KeyValuePair<int, String>(level, parent + detail)); 
     return result; 
    } 
+0

semble très prometteur. Merci beaucoup. Je vais le tester sur quelques exemples de fichiers XML et mettre à jour cette question d'ici demain. – Rumtis