2011-01-01 13 views
1

私はHTMLコードを解析する必要があります。具体的には、すべての表の各行の各セルを解析します。各行は単一のオブジェクトを表し、各セルは異なるプロパティを表します。私は、(不要なHTMLコードなしで)すべてのデータを含むXMLファイルを書くことができるようにこれらを解析したいと思います。私は正常にHTMLファイルから各列を解析することができましたが、今私は私のオプションがXMLファイルにこれを書くためのものであるか分からない。私はうんざりしています。テーブル、C#でHTMLの敏捷性を持つセルを解析する

HTML:

<tr><tr> 
<td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF"> 
    1 
</td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="left"> 
     <a href="/ice/player.htm?id=8471675">Sidney Crosby</a> 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="center"> 
     PIT 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="center"> 
     C 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     39 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     32 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     33 
    </td> 
    <td class="statBox sorted" style="border-width:0px 1px 1px 0px; background-color: #E0E0E0" align="right"> 
     <font color="#000000"> 
      65 
     </font> 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     20 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     29 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     10 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     1 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     3 
    </td> 
    <td class="statBox" style="border-width:0px 0px 1px 0px; background-color: #FFFFFF" align="right"> 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     0 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     154 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     20.8 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     21:54 
    </td> 
    <td class="statBox" style="border-width:0px 1px 1px 0px; background-color: #FFFFFF" align="right"> 
     22.6 
    </td> 
    <td class="statBox" style="border-width:0px 0px 1px 0px; background-color: #FFFFFF" align="right"> 
     55.7 
    </td> 
</tr></tr> 

のC#:

using HtmlAgilityPack; 

namespace Stats 
{ 
    class StatsParser 
    { 
     private string htmlCode; 
     private static string fileName = "[" + DateTime.Now.ToShortDateString() + " NHL Stats].xml"; 

     public StatsParser(string htmlCode) 
     { 
      this.htmlCode = htmlCode; 
      this.ParseHtml(); 
     } 

     public void ParseHtml() 
    { 
     HtmlDocument doc = new HtmlDocument(); 
     doc.LoadHtml(htmlCode); 

     try 
     { 
      // Get all tables in the document 
      HtmlNodeCollection tables = doc.DocumentNode.SelectNodes("//table"); 

      // Iterate all rows in the first table 
      HtmlNodeCollection rows = tables[0].SelectNodes(".//tr"); 
      for (int i = 0; i < rows.Count; ++i) 
      { 

       // Iterate all columns in this row 
       HtmlNodeCollection cols = rows[i].SelectNodes(".//td[@class='statBox']"); 
       for (int j = 0; j < cols.Count; ++j) 
       { 

        // Get the value of the column and print it 
        string value = cols[j].InnerText; 
        if (value!="") 
         System.Windows.MessageBox.Show(value); 
       } 
      } 
     } 
     catch (NullReferenceException) 
     { 
      System.Windows.Forms.MessageBox.Show("Exception!!"); 
     } 
    } 

XML:

<?xml version="1.0" encoding="utf-8" ?> 

<Stats Date="2011-01-01"> 
    <Player Rank="1"> 
    <Name>Sidney Crosby</Name> 
    <Team>PIT</Team> 
    <Position>C</Position> 
    <GamesPlayed>39</GamesPlayed> 
    <Goals>32</Goals> 
    <Assists>33</Assists> 
    </Player> 
</Stats> 
+0

は、あなたは、あなたが好きなXML出力のサンプルを与えることができますか? – Cameron

+0

FWIWを使用すると、XPathをより効果的に使用した場合、 "解析"コードを大幅に簡素化できます。 'doc.DocumentNode.SelectNodes(" // table [1]/tr/td [@ class = 'statBox'] ")'は、最初のテーブルのすべての 'statBox'セルを与えます。 –

+0

@Cameron、私はXMLの抜粋を追加しました。 –

答えて

1

MSDNを見回した後、私はようやく私の問題への実装の解決策を見つけた:

using System; 
    using HtmlAgilityPack; 
    using System.Xml; 

    namespace HockeyStats 
    { 
     class StatsParser 
     { 
      private string htmlCode; 
      private static string fileName = "[" + DateTime.Now.ToShortDateString() + " NHL Stats].xml"; 

      public StatsParser(string htmlCode) 
      { 
       this.htmlCode = htmlCode; 

       this.ParseHtml(); 
      } 

      public void ParseHtml() 
      { 

       HtmlDocument doc = new HtmlDocument(); 
       doc.LoadHtml(htmlCode); 
       XmlWriter writer = null; 

       try 
       { 
        // Create an XmlWriterSettings object with the correct options. 
        XmlWriterSettings settings = new XmlWriterSettings(); 
        settings.Indent = true; 
        settings.IndentChars = (" "); 
        settings.OmitXmlDeclaration = false; 

        // Create the XmlWriter object and write some content. 
        writer = XmlWriter.Create(@"..\..\"+fileName, settings); 
        writer.WriteStartElement("Stats"); 
        writer.WriteAttributeString("Date", DateTime.Now.ToShortDateString()); 

       // Iterate all rows within another row 
       HtmlNodeCollection rows = doc.DocumentNode.SelectNodes(".//tr/tr"); 
       for (int i = 0; i < rows.Count; ++i) 
       { 
        // Iterate all columns in this row 
        HtmlNodeCollection cols = rows[i].SelectNodes(".//td[@class='statBox']"); 
        for (int j = 0; j < 20; ++j) 
        { 
           switch (j) 
           { 
            case 0: 
             { 
              writer.WriteStartElement("Player"); 
              writer.WriteAttributeString("Rank", cols[j].InnerText.Trim()); break; 
             } 
            case 1: writer.WriteElementString("Name", cols[j].InnerText.Trim()); break; 
            case 2: writer.WriteElementString("Team", cols[j].InnerText.Trim()); break; 
            case 3: writer.WriteElementString("Pos", cols[j].InnerText.Trim()); break; 
            case 4: writer.WriteElementString("GP", cols[j].InnerText.Trim()); break; 
            case 5: writer.WriteElementString("G", cols[j].InnerText.Trim()); break; 
            case 6: writer.WriteElementString("A", cols[j].InnerText.Trim()); break; 
            case 7: writer.WriteElementString("PlusMinus", cols[j].InnerText.Trim()); break; 
            case 8: writer.WriteElementString("PIM", cols[j].InnerText); break; 
            case 9: writer.WriteElementString("PP", cols[j].InnerText); break; 
            case 10: writer.WriteElementString("SH", cols[j].InnerText); break; 
            case 11: writer.WriteElementString("GW", cols[j].InnerText); break; 
            case 12: writer.WriteElementString("OT", cols[j].InnerText); break; 
            case 13: writer.WriteElementString("Shots", cols[j].InnerText); break; 
            case 14: writer.WriteElementString("ShotPctg", cols[j].InnerText); break; 
            case 15: writer.WriteElementString("TOIPerGame", cols[j].InnerText); break; 
            case 16: writer.WriteElementString("ShiftsPerGame", cols[j].InnerText); break; 
            case 17: writer.WriteElementString("FOWinPctg", cols[j].InnerText); break; 

           } 
          } 
         } 
         writer.WriteEndElement(); 
        } 
        writer.WriteEndElement(); 
        writer.Flush(); 
       } 
       finally 
       { 
        if (writer != null) 
         writer.Close(); 
       } 
      } 
     } 
    } 
出力として、次のXMLファイル与え

:私は私のコメントで意図していた何

<?xml version="1.0" encoding="utf-8" ?> 
<Stats Date="2011-01-01"> 
<Player Rank="1"> 
    <Name>Sidney Crosby</Name> 
    <Team>PIT</Team> 
    <Pos>C</Pos> 
    <GP>39</GP> 
    <G>32</G> 
    <A>33</A> 
    <PlusMinus>20</PlusMinus> 
    <PIM>29</PIM> 
    <PP>10</PP> 
    <SH>1</SH> 
    <GW>3</GW> 
    <Shots>0</Shots> 
    <ShotPctg>154</ShotPctg> 
    <TOIPerGame>20.8</TOIPerGame> 
    <ShiftsPerGame>21:54</ShiftsPerGame> 
    <FOWinPctg>22.6</FOWinPctg> 
</Player> 
</Stats> 
1

は、あなたが正しいXPathを持つことはあなたのために何ができるかのコードで(ネストされたループを)やっているということでした。 LINQ-to-XMLを使用すると、これをさらに簡単に書くことができます。しかし、XMLファイルをどのようにフォーマットしたいのか分かったので、私たちは独自の答えを提供することができます。私はそうのようなParseHtml()方法を記述します

public void ParseHtml() 
{ 
    var htmlDoc = new HtmlDocument(); 
    htmlDoc.LoadHtml(htmlCode); 
    var cells = htmlDoc.DocumentNode 
            // use the right XPath rather than looping manually 
         .SelectNodes(@"//tr/tr/td[@class='statBox']") 
         .Select(node => node.InnerText.Trim()) 
         .ToList(); 
    var elementNames = new[] { "Name", "Team", "Pos", "GP", "G", "A", "PlusMinus", "PIM", "PP", "SH", "GW", "OT", "Shots", "ShotPctg", "TOIPerGame", "ShiftsPerGame", "FOWinPctg", "UnknownField" }; 
    var xmlDoc = 
     new XElement("Stats", new XAttribute("Date", DateTime.Now.ToShortDateString()), 
      new XElement("Player", new XAttribute("Rank", cells.First()), 
       // generate the elements based on the parsed cells 
       cells.Skip(1) 
        .Zip(elementNames, (Value, Name) => new XElement(Name, Value)) 
        .Where(element => !String.IsNullOrEmpty(element.Value)) 
      ) 
     ); 

    // save to your file 
    xmlDoc.Save(filepath); 
} 

は出力を生成します。

<?xml version="1.0" encoding="utf-8"?> 
<Stats Date="1/3/2011"> 
    <Player Rank="1"> 
    <Name>Sidney Crosby</Name> 
    <Team>PIT</Team> 
    <Pos>C</Pos> 
    <GP>39</GP> 
    <G>32</G> 
    <A>33</A> 
    <PlusMinus>20</PlusMinus> 
    <PIM>29</PIM> 
    <PP>10</PP> 
    <SH>1</SH> 
    <GW>3</GW> 
    <Shots>0</Shots> 
    <ShotPctg>154</ShotPctg> 
    <TOIPerGame>20.8</TOIPerGame> 
    <ShiftsPerGame>21:54</ShiftsPerGame> 
    <FOWinPctg>22.6</FOWinPctg> 
    <UnknownField>55.7</UnknownField> 
    </Player> 
</Stats> 
+0

でこれを行う簡単な方法があれば、ParseHtml()メソッドを構築しようとしていますが、エラー: 'HtmlAgilityPack.HtmlNodeCollection'に 'SelectSingleNode'の定義が含まれておらず、 'HtmlAgilityPack.HtmlNodeCollection'タイプの最初の引数を受け入れる拡張メソッド 'SelectSingleNode'がありませんでした。 usingディレクティブまたはアセンブリ参照がありません) –

+0

この問題を修正しました... 55.7の値が追加されました。 –

+0

P.S.、バージョン1.4.0.0のHtmlAgilityPackおよび.NET 3.5 –

関連する問題