Опубликован: 05.08.2010 | Уровень: специалист | Доступ: платный
Лекция 4:

Разработка компонента WPF и анализатора HTML-таблиц

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

Упражнение 2. Разработка утилиты преобразования HTML-таблиц <table> в объекты DataSet

Для начала используем программные тесты с кодом HTML. Рассмотрим два способа разбора XML -кода. Для реализации этих способов воспользуемся консольным приложением.

  • Командой меню File/Add/New Project добавьте к решению новый проект с именем ConvertTables и назначьте его стартовым

Оболочка автоматически создала файл Program.cs с точкой входа в приложение.

Пример 1. Применение XML-анализатора

Вначале рассмотрим более слабый способ " Convert HTML Table to Array/Dataset " из "http://forums.asp.net/t/947241.aspx", который требует предварительной подготовки исходной таблицы.

  • В Solution Explorer вызовите контекстное меню для корня проекта ConvertTables и командой Add/Class добавьте класс с именем Convert1
  • Заполните класс Convert1 следующим кодом
using System;
using System.Collections.Generic;
using System.Text;
    
using System.Data;
using System.Xml;
    
namespace ConvertTables
{
    class Convert1 // Source: "http://forums.asp.net/t/947241.aspx"
    {
        public void HtmlToDataTable()
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(@"
                <table border='1' cellpadding='0' cellspacing='0'> 
                  <tr>
                    <td width='50%'>cell 1a</td>
                    <td width='50%'>cell 1b</td>
                  </tr>
                  <tr>
                    <td width='50%'>cell 2a</td>
                    <td width='50%'>cell 2b</td>
                  </tr>
                </table>
                        ");
    
            DataTable dt = new DataTable();
            dt.Columns.Add("Col1");
            dt.Columns.Add("Col2");
    
            foreach (XmlNode ndRow in doc.DocumentElement.ChildNodes)
            {
                DataRow dr = dt.NewRow();
                for (int colIndex = 0; colIndex < ndRow.ChildNodes.Count; colIndex++)
                    dr[colIndex] = ndRow.ChildNodes[colIndex].InnerText;
                dt.Rows.Add(dr);
            }
    
            // Выводим на консоль
            foreach (DataRow row in dt.Rows)
                Console.WriteLine("{0}    {1}", row["Col1"], row["Col2"]);
        }
    }
}
  • Добавьте в файл Program.cs с функцией Main() код выполнения класса Convert1
using System;
using System.Collections.Generic;
using System.Text;
    
namespace ConvertTables
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.White;
    
            Convert1 convert1 = new Convert1();
            convert1.HtmlToDataTable();
    
            Console.ReadLine(); // Для задержки окна
        }
    }
}
  • Запустите проект - должен получиться следующий результат
cell 1a            cell 1b
cell 2a            cell 2b

Пример 2. Применение регулярных выражений

Применим код " Convert HTML tables to a DataSet " из "http://www.dotnetfunda.com/articles/article51.aspx". Этот подход более универсальный и может применяться как самостоятельно, так и в комбинации с первым способом. Вначале приведем код вместе с тестом, а затем приспособим его к своей задаче.

  • В Solution Explorer вызовите контекстное меню для корня проекта ConvertTables и командой Add/Class добавьте класс с именем Convert2
  • Наполните класс Convert2 следующим кодом
using System;
using System.Collections.Generic;
using System.Text;
    
using System.Data;
using System.Xml;
using System.Text.RegularExpressions;
    
namespace ConvertTables
{
    class Convert2 // Source: "http://www.dotnetfunda.com/articles/article51.aspx"
    {
        public String GetHTML()
        {
            StringBuilder sb = new StringBuilder();
    
            sb.AppendLine("<!DOCTYPE HTML PUBLIC " +
                "-//W3C//DTD HTML 4.01 Transitional//EN" +
                "http://www.w3.org/TR/html4/loose.dtd" +
                ">");
            sb.AppendLine("<html>");
            sb.AppendLine("<head>");
            sb.AppendLine("<meta http-equiv=" +
                "Content-Type" +
                " content=" +
                "text/html; charset=iso-8859-1" +
                "> ");
    
            // Первая таблица (с заголовком)
            sb.AppendLine("<title>Title</title>");
            sb.AppendLine("</head>");
            sb.AppendLine("<body>");
            sb.AppendLine("<table>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<th>Table 1 - Header 1</th>");
            sb.AppendLine("<th>Table 1 - Header 2</th>");
            sb.AppendLine("<th>Table 1 - Header 3</th>");
            sb.AppendLine("</tr>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 1 - Row 1 - Column 1</td>");
            sb.AppendLine("<td>Table 1 - Row 1 - Column 2</td>");
            sb.AppendLine("<td>Table 1 - Row 1 - Column 3</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 1 - Row 2 - Column 1</td>");
            sb.AppendLine("<td>Table 1 - Row 2 - Column 2</td>");
            sb.AppendLine("<td>Table 1 - Row 2 - Column 3</td>");
            sb.AppendLine("</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 1 - Row 3 - Column 1</td>");
            sb.AppendLine("<td>Table 1 - Row 3 - Column 2</td>");
            sb.AppendLine("<td>Table 1 - Row 3 - Column 3</td>");
            sb.AppendLine("</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("</table>");
    
            // Вторая таблица (без заголовка)
            sb.AppendLine("<table>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 2 - Row 1 - Column 1</td>");
            sb.AppendLine("<td>Table 2 - Row 1 - Column 2</td>");
            sb.AppendLine("<td>Table 2 - Row 1 - Column 3</td>");
            sb.AppendLine("</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 2 - Row 2 - Column 1</td>");
            sb.AppendLine("<td>Table 2 - Row 2 - Column 2</td>");
            sb.AppendLine("<td>Table 2 - Row 2 - Column 3</td>");
            sb.AppendLine("</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("<tr>");
            sb.AppendLine("<td>Table 2 - Row 3 - Column 1</td>");
            sb.AppendLine("<td>Table 2 - Row 3 - Column 2</td>");
            sb.AppendLine("<td>Table 2 - Row 3 - Column 3</td>");
            sb.AppendLine("</td>");
            sb.AppendLine("</tr>");
            sb.AppendLine("</table>");
    
            sb.AppendLine("</body>");
            sb.AppendLine("</html>");
    
            return sb.ToString();
        }
    
        public DataSet ConvertHTMLTablesToDataSet(String HTML)
        {
            // Локальные сылки
            DataSet ds = new DataSet();
            DataTable dt;
            DataRow dr;
            // DataColumn dc;
    
            bool HeadersExist = false;  // Флаг заголовка таблицы
            int iCurrentColumn = 0;     // Счетчик столбцов
            int iCurrentRow = 0;        // Счетчик строк
    
            // Регулярные выражения
            String TableExpression = "<table[^>]*>(.*?)</table>";
            String HeaderExpression = "<th[^>]*>(.*?)</th>";
            String RowExpression = "<tr[^>]*>(.*?)</tr>";
            String ColumnExpression = "<td[^>]*>(.*?)</td>";
            RegexOptions options = RegexOptions.Multiline |
                                   RegexOptions.Singleline |
                                   RegexOptions.IgnoreCase;
    
            // Заполняем коллекцию соответствий для всех таблиц HTML
            MatchCollection Tables = Regex.Matches(HTML, TableExpression, options);
    
            // Проходим по всем таблицам 
            foreach (Match Table in Tables)
            {
                // Сбрасываем счетчик строки и флаг заголовка
                HeadersExist = false;
                iCurrentRow = 0;
    
                // Создаем объект новой таблицы и наполняем его
                dt = new DataTable();
    
                /* Создаем соответствующее количество столбцов 
                 * для текущей таблицы (используем заголовки, 
                 * если они существуют, иначе используем 
                 * заданные по умолчанию названия)                
                 */
                if (Table.Value.Contains("<th"))
                {
                    HeadersExist = true;// Таблица содержит заголовок
                    // Заполняем коллекцию соответствий для всех <th> в таблице
                    MatchCollection Headers = Regex.Matches(
                        Table.Value, HeaderExpression, options);
    
                    // Добавляем столбцы с именами из строки заголовков текущей таблицы
                    foreach (Match Header in Headers)
                    {
                        dt.Columns.Add(Header.Groups[1].ToString());
                    }
                }
                else
                {
                    Match tab = Regex.Matches(Table.Value, TableExpression, options)[0];
                    Match row = Regex.Matches(tab.ToString(), RowExpression, options)[0];
                    int count = Regex.Matches(row.ToString(), ColumnExpression, options).Count;
    
                    // Строки заголовков нет, добавляем дежурные имена
                    for (int iColumns = 0; iColumns < count; iColumns++)
                        dt.Columns.Add("Column" + iColumns);
                }
    
                // Извлекаем коллекцию строк текущей таблицы
                MatchCollection Rows = Regex.Matches(Table.Value, RowExpression, options);
    
                // Добавляем строки в объект DataRow
                foreach (Match Row in Rows)
                {
                    // Игнорируем строку заголовка
                    if (iCurrentRow != 0 || HeadersExist != true)
                    {
                        dr = dt.NewRow();
                        iCurrentColumn = 0;
                        // Извлекаем коллекцию столбцов текущей строки
                        MatchCollection Columns = Regex.Matches(Row.Value, ColumnExpression, options);
                        foreach (Match Column in Columns)
                        {
                            dr[iCurrentColumn] = Column.Groups[1].ToString();
                            iCurrentColumn++;
                        }
    
                        dt.Rows.Add(dr);
                    }
    
                    iCurrentRow++;
                }
    
                ds.Tables.Add(dt);
            }
    
            return ds;
        }
    }
}
  • Удалите в файле Program.cs код выполнения класса Convert1 и добавьте код выполнения класса Convert2. В результате должно получиться следующее
using System;
using System.Collections.Generic;
using System.Text;
    
using System.Data;
    
namespace ConvertTables
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.White;
    
            Convert2 convert2 = new Convert2();
    
            String source = convert2.GetHTML();
            DataSet dataSet = convert2.ConvertHTMLTablesToDataSet(source);
    
            for (int i = 0; i < dataSet.Tables.Count; i++)
            {
                // Распечатываем заголовки столбцов
                foreach (DataColumn col in dataSet.Tables[i].Columns)
                    Console.Write("{0}    ", col.ColumnName);
                Console.WriteLine();
    
                // Распечатываем строки
                foreach (DataRow row in dataSet.Tables[i].Rows)
                {
                    foreach (DataColumn col in dataSet.Tables[i].Columns)
                        Console.Write("{0}    ", row[col].ToString());
                    Console.WriteLine();
                }
    
                Console.WriteLine();
            }
    
            Console.ReadLine(); // Для задержки окна
        }
    }
}
  • Запустите проект - должен получиться следующий результат
Table 1 - Header 1     Table 1 - Header 2     Table 1 - Header 3
Table 1 - Row 1 - Column 1     Table 1 - Row 1 - Column 2     Table 1 - Row 1 - Column 3
Table 1 - Row 2 - Column 1     Table 1 - Row 2 - Column 2     Table 1 - Row 2 - Column 3
Table 1 - Row 3 - Column 1     Table 1 - Row 3 - Column 2     Table 1 - Row 3 - Column 3

Column0     Column1     Column2
Table 2 - Row 1 - Column 1     Table 2 - Row 1 - Column 2     Table 2 - Row 1 - Column 3
Table 2 - Row 2 - Column 1     Table 2 - Row 2 - Column 2     Table 2 - Row 2 - Column 3
Table 2 - Row 3 - Column 1     Table 2 - Row 3 - Column 2     Table 2 - Row 3 - Column 3
< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Dmitriy Ivanchenko
Dmitriy Ivanchenko
Украина, Кировоград, Виктория-П, 2011
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974