Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Friday, September 2, 2011

Быстрое сохранение в XML класса Font, Color, enum...

Вот лень мне было по кусочкам Font сохранять в XML. Нашел вот такой способ:

public static XmlElement AddElementByConverter<T>(XmlElement parentNode, string nodeName, T attrValue)
{
  TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
  string value = converter.ConvertToString(attrValue));
  .... ну и тут дальше как обычно
}


И загружать просто:

public static T ReadByConverter<T>(XmlNode element, string path, T defaultValue)
{
   T nodeValue = defaultValue;
   XmlNode node = element.SelectSingleNode(path);

   .........
   TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
   nodeValue = (T) converter.ConvertFromString(valueString);
   if (nodeValue == null)
      nodeValue = defaultValue;
   .........
   return nodeValue;
}


Такая конструкция замечательно глотает и Font и Color и любой enum.
Типа кодюлька номер раз :)

Monday, November 29, 2010

Задача для архитектора (часть 2)

Хранение в БД

С таблицей рецептур в общем-то все понятно. Делаем таблицу Receipt с полям: ID (ключ), Title (название рецептуры), Description (краткое описание – заказчик не просил, но думаю не помешает), CreatedDate (дата создания, тоже пригодится).
А вот как хранить команды рецептуры это хороший вопрос. Команды разного типа. Общего у них: ID (ключ), ReceiptID (ID рецептуры), CommandType (тип команды). А различного у них – параметры команды. Для загрузки компонентов это ID компонента и вес в кг. Для паузы – величина задержки в сек. И т.д.
Вариант хранения всех команд в одной таблице мне не нравится – будет много пустых столбцов, а добавлять новые типы команд будет затруднительно. Вариант хранения каждого типа команд в отдельной таблице тоже не нравится – слишком сложно будет читать данные. Для такой просто задачи это перебор.
И тут срабатывает ограничитель лени J Он говорит, что задача слишком простая, база данных слишком локальная и вообще надо быть проще… Не могу с ней не согласиться.
Вариантов упрощения жизни у меня два. Первый – сделать отдельную таблицу команд ReceiptCommand со всеми перечисленными выше полями, но параметры хранить в столбце Params типа string в виде XML. Тогда все будет просто – все что нужно будет сделать, это прочитать данные из таблицы команд для нужного ReceiptID, создать нужные типы команд и отдать им их XML-параметры. А уже каждая команда для себя решит как ей понять свои параметры. Сохранение точно так же, только каждая команда сохраняет свои параметры в виде XML и мы записываем их в это поле.
Второй вариант еще проще, но с точки зрения архитектуры менее красивый – текстовый столбец Commands в таблице Receipt. Тип у него text. А хранить я в нем буду список команд в виде XML, т.е. даже не раскладывать команды по строкам. Никаких “лишних” таблиц, чтение и запись данных будет элементарная. Правда с преобразованием в список будет немного возни, но тут тоже не сложно – рецептура выбирается один раз при старте системы, т.е. достаточно редко, а список рецептур редактируется тоже редко и не требует постоянных преобразований. Так что все получится.
Важно! Этим примером я не призываю ломать типизацию, но хочу обратить внимание, что иногда условия задачи складываются так, что можно позволить себе упрощение архитектуры без ее ухудшения. Конечно, не нужно доводить эту идею до маразма – а то можно дойти до одной таблицы и одного поля, в которое нужно будет писать XML содержащий вообще все. Нет, конечно. Но конкретно для хранения параметров некоторых объектов, которые отличаются только этими параметрами – вполне можно.
В результате я выбрал второй вариант, совсем простой. Аргументы у меня были (если не считать лени) такие: при создании рецептуры и при чтении списка команд оба варианты примерно равноправны. А вот при редактировании будут различия. В первом варианте нужно будет либо удалять все строки, соответствующие ID рецептуры и потом сохранять их заново, либо, что значительно сложнее, пытаться вносить в них изменения. А если стирать и заносить заново, то какая разница между этим и вторым вариантом, когда я храню сразу XML со списком команд? Задачи получить нужную команду по ее номеру у меня нет - список команд не разделим на части и команда по отдельности смысла не имеет. Запросы "дай мне все рецептуры, где используется этот тип команды" тоже смысла не имеют. Получается что второй вариант проще. Но - только в данных конкретных условиях задачи.
Продолжение следует...

Thursday, November 25, 2010

XDocument и Double

Будьте внимательны - между двумя строчками кода

Weight = 22.44;
new XAttribute("weight", Weight.ToString())
new XAttribute("weight", Weight)


есть большая разница в случае русской культуры. В первом случае в XML будет записано 22,44 тогда как во втором 22.44 (через точку) и при попытке прочитать это значение будет ошибка.

Но ведь XML должен быть корректным не зависимо от используемой культуры (может быть он будет прочитан совсем на другом компьютере, чем записан), поэтому всегда используйте второй вариант, а при чтении устанавливайте культуру в en-US:

static CultureInfo cultureEnUS = new CultureInfo("en-US");

XAttribute weightAttr = element.Attribute("weight");
if (weightAttr != null)
{
    Weight = double.Parse(weightAttr.Value, cultureEnUS);
}

Wednesday, November 24, 2010

Почему XML

Нам нужно сохранить данные в файл. Нет ничего проще – взяли да и записали через запятую все данные, если их много – можно по-строчно. Проблем нет, пока… Пока не окажется что внутри данных тоже может быть запятая, а значит нужно данные ограничивать кавычками, как в формате CSV. Потом оказывается к данным нужно дописывать комментарии, типы данных, имена полей (иначе как те кому файл предназначен поймут где тут что?)… Да и хорошо бы сделать так, что новые форматы работали бы со старым кодом и наоборот, т.е. обновления не мешали друг другу…

Любое изменение формата записываемых данных ведет к изменению парсера, который их читает. Конечно, делать парсер под каждый случай  - это лишние затраты времени и сил. Да и лень просто…

XML позволяет записывать любые данные в формате, для которого уже существует готовый парер, причем фактически для всех платформ и языков. XML никак не ограничивает ни состав данных, ни их структуру. Это просто формат записи.

Единый формат записи данных особенно актуален для Интернета, когда передающая и принимающая стороны могут и не знать о существовании друг друга.

Прочитать о формате XML можно в Википедии.
Что еще позволяет формат XML:
·         искать данные с помощью XPath, делать запросы как к базе данных
·         хранить иерархические и древовидные данные
·         проверять формат файла на соответствие его определенной схеме
·         преобразовывать XML в другие форматы
·         отображать данные в браузере, с помощью CSS-стилей
·         легко и просто редактировать данные с помощью XML-редакторов
·         встроенная поддержка XML в библиотеке .NET
·         возможность автоматического сохранения данных в XML формат с помощью сериализации
XML формат поддерживается почти везде –от баз данных до встроенных систем.

Минусы XML формата напрямую связаны с тем, что это текстовый формат:
·         Объем XML-файла существенно больше, чем просто бинарный файл.
·         Данные не типизированы, т.е. все записываются в текстовом виде.

Конечно, эти вопросы можно решить, например, с помощью архивирования и схем валидации. Зато готовое решение для формата хранения данных и множество уже реализованных возможностей делает XML очень удобным.

В .NET для работы с XML используются классы XDocument (начиная с версии 4) или XmlDocument.