2017-09-06 12 views
2

問題:私はXMLを解析し、XML内の各ノードのためのオブジェクトを作成しようとしている再帰的なスタイルのリストにXML構造を再構築/ XMLReaderの代替

問題:私のXMLは任意の順序でノードを持つ、といくつかの他のノードの子ノードであるため

は、私は論理的に、.NET 1.1とのXmlNodeクラスを使用せずにそれらを解析するために苦労しています。

ノート:XMLReaderのみを.Net Standard 1.0に制限して使用したいので、余分なライブラリをインストールしたくありません。 (https://docs.microsoft.com/en-us/dotnet/standard/net-standard

現在、各ノードにオブジェクトを作成します。各オブジェクトには、追加する子コンポーネントのリストが含まれています(子ノードを見つける必要があります)。しかし、私は再帰的にXMLを検索し、構造体をリスト/リストのリストに正しく生成することはできません。

私のコード

using System.IO; 
using System.Xml; 
using System.Xml.Linq; 

namespace ConsoleApp1 
{ 
    class Program 
    { 
    static List<UIComponent> components = new List<UIComponent>(); 

    static void Main(string[] args) 
    { 
     String path = "C:\\Users\\admin\\Desktop\\test.xml"; 
     parseXML(path); 
    } 


    private static UIComponent addToLowestChild(UIComponent parent, UIComponent child) 
    { 
     for(int i=0;i<parent.getChildren().Count;++i) 
     { 

      if (parent.getChildren().Count > 0) 
      { 
       foreach (UIComponent kid1 in parent.getChildren()) 
       { 
        if (kid1.getChildren().Count > 0) 
        { 
         addToLowestChild(kid1, child); 
        } 
       } 
      } 
     } 
     return parent; 
    } 

    private static UIComponent ChildTest(int depth,UIComponent parent,UIComponent child) 
    { 
     //i=depth for item 4, if i is set to 1 first 
     for (int i = 1; i < depth; ++i) 
      { 
       if (parent.getChildren().Count > 0) 
       { 
        if (i > 1) 
        { 
        ChildTest(i, parent.getChildren()[parent.getChildren().Count - 1], child); 
        } 
        else 
        { 
        parent.getChildren()[parent.getChildren().Count - 1].addChild(child); 
        break; 
        } 
       } 
       else 
       { 
        parent.addChild(child); 
        break; 
       } 
      } 


     return parent; 
    } 

    private static void parseXML(string path) 
    { 
     //read the xml file into one string 
     string[] lines = System.IO.File.ReadAllLines(path); 
     string xmlContent = ""; 
     foreach (string line in lines) 
     { 
      xmlContent += line; 
     } 

     UIComponent currentComponent = null; 

     //parse the xml content 
     using (XmlReader reader = XmlReader.Create(new StringReader(xmlContent))) 
     { 

      while (reader.Read()) 
      { 

       int currentDepth = 0; 
       // Console.WriteLine(reader.Name+" depth:"+reader.Depth); 
       if (reader.Depth > 0) //ignore ground level elements such as <XML> and <UI> 
       { 


        switch (reader.NodeType) 
        { 
         case XmlNodeType.Element: 
          if (currentComponent == null || reader.Depth==currentDepth) 
          { 
           currentComponent = new UIComponent(reader.Name); 
          } 
          else 
          { 
           UIComponent childComponent = new UIComponent(reader.Name); 
           //currentComponent.addChild(childComponent); 
           ChildTest(reader.Depth,currentComponent,childComponent); 
          } 
          break; 

         case XmlNodeType.Text: 
          break; 
         case XmlNodeType.XmlDeclaration: 
         case XmlNodeType.ProcessingInstruction: 
          break; 
         case XmlNodeType.Comment: 
          break; 
         case XmlNodeType.EndElement: 
          if (reader.Depth == 1 && currentComponent!=null) 
          { 
           components.Add(currentComponent); 
           currentComponent = null; 
          } 
          break; 
         default: break; 
        } 
       } 

      } 
     } 
    } 

私のテストデータ

<?xml version="1.0" encoding="UTF-8"?> 
<UI> 
    <window x="5"> 
    <Button2 value=""> 
     <Button3 y=""> 
     </Button3> 
     <Button4> 
      <Button6 value=""></Button6> 
      <Button5 value=""></Button5> 
     </Button4> 
    </Button2> 
    </window> 
    <window></window> 
    <heading></heading> 
</UI> 

出力:私が欲しいもの

-Window 
    |-Button 2 
    |-- Button 3 
    |-- Button 4 
    |-- Button 6 
    |-- Button 5 
-Window 
-Heading 

-Window 
    |-Button 2 
    |-- Button 3 
    |-- Button 4 
     |-- Button 6 
     |-- Button 5 
-Window 
-Heading 
+0

は、ここでのXmlReaderの説明からだ:「*は、読者を表します高速でキャッシュされていないXMLデータへのフォワード専用アクセスを提供します* "。あなたはそれを実際に追加できると思いますか? –

+0

* .net 1.0 *とは何ですか? –

+1

将来の読者の皆様には、これに対処するための質問を更新しました。 @IvanStoevの助けをありがとう! – D3181

答えて

2

必要なのは、現在処理中のノードのスタックを維持することです。 StartElementを押すたびに、新しいノードを作成し、属性を読み込んで親ノードまたはルートノードリストに追加し、要素が空でない場合は(<window />など)、それをスタックにプッシュします。 EndElementを押すと、スタックの最後の要素がポップ(削除)されます。スタックトップ要素は、現在処理中のノードを表します。

class Node 
{ 
    public string Name; 
    public List<Node> Children = new List<Node>(); 
    public Dictionary<string, string> Attributes = new Dictionary<string, string>(); 
    public override string ToString() => Name; 
} 

はこのようなものが考えられます:このような単純なクラスのリストにXMLを解析し、行動にそれを置く

static List<Node> ParseXML(string xmlContent) 
{ 
    using (var reader = XmlReader.Create(new StringReader(xmlContent))) 
    { 
     var rootNodes = new List<Node>(); 
     var nodeStack = new Stack<Node>(); 
     while (reader.Read()) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.Element: 
        var node = new Node { Name = reader.Name }; 
        if (reader.MoveToFirstAttribute()) 
        { 
         // Read the attributes 
         do 
         { 
          node.Attributes.Add(reader.Name, reader.Value); 
         } 
         while (reader.MoveToNextAttribute()); 
         // Move back to element 
         reader.MoveToElement(); 
        } 
        var nodes = nodeStack.Count > 0 ? nodeStack.Peek().Children : rootNodes; 
        nodes.Add(node); 
        if (!reader.IsEmptyElement) 
         nodeStack.Push(node); 
        break; 

       case XmlNodeType.EndElement: 
        nodeStack.Pop(); 
        break; 
      } 
     } 
     return rootNodes; 
    } 
関連する問題