• Введение: работа с XML
  • XML или не XML?
  • Сравнение XML с другими текстовыми форматами
  • Различные способы хранения данных в виде текста
  • Иерархическая структура XML-данных
  • Другие возможности XML
  • Различные способы работы с XML
  • Простой пример, иллюстрирующий применение модели XML DOM и однонаправленного чтения-записи XML-документов
  • Пример: содержимое XML-файла
  • XML DOM
  • Модель однонаправленного чтения-записи XML-данных
  • Повышение производительности приложения перекладыванием работы на другие программы
  • Избегайте выполнения сложных преобразований данных на устройстве
  • Избегайте выполнения сложного поиска данных на устройстве
  • Рассмотрите возможность исключения необязательной информации перед отправкой данных на устройство
  • Когда не стоит перекладывать выполнение работы на сервер
  • Резюме 
  • ГЛАВА 10

    Производительность и XML 

    Введение: работа с XML

    XML быстро становится излюбленным текстовым форматом, применяемым для хранения и передачи данных. Причины его повышенной по сравнению с обычными текстовыми файлами популярности имеют два аспекта: 1) иерархичность — данные могут легко сохраняться с использованием отношений "родительский-дочерний" между ними, и 2) полуструктурированность — XML допускает значительную гибкость в управлении структурной информацией, применяемой к данным, обмен которыми осуществляется. XML-данные могут либо жестко привязываться к определенной схеме (сама схема также может задаваться в виде XML-документа), либо передаваться как таковые в свободной форме без каких-либо формальных указаний относительно содержимого документа.

    XML имеет много сходства с другим популярным форматом кодирования информации — HTML. HTML — это аббревиатура от HyperText Markup Language — язык гипертекстовой разметки, что, говоря простыми словами, означает использование "текстовых дескрипторов, описывающих то, как выглядит документ". Аналогичным образом, XML — это extensible Markup Language — расширяемый язык разметки документов, что в переводе на обычный язык означает использование "текстовых дескрипторов, описывающих данные". Язык XML является продуктом накопления опыта в процессе эволюции HTML, и оба эти языка происходят от более старого абстрактного формата SGML (Standard Generalized Markup Language — стандартный обобщенный язык разметки). Полуструктурированный иерархический текстовый формат HTML на практике доказал свою большую гибкость по сравнению со многими существующими до этого двоичными форматами. Популярные адаптированные варианты HTML, а затем и XML продемонстрировали, что компактностью двоичных форматов часто имеет смысл пожертвовать ради гибкости, расширяемости и переносимости текстовых форматов. Синтаксис дескрипторов и атрибутов, используемый в HTML для описания внешнего вида и содержимого документов, рассматривался многими разработчиками как мощная, расширяемая модель описания данных. Недостатки HTML обусловлены его быстрой эволюцией; поскольку в течение ряда лет этот формат претерпел естественные эволюционные изменения, в его синтаксисе имеются несоответствия, которые при последовательном подходе к разработке языка считались бы недопустимыми.

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

    Как и HTML, язык XML имел успех постольку, поскольку была достигнута договоренность о его использовании для обмена информацией между различными системами. Важность широкого принятия этой методики невозможно переоценить. После того как формат получает всеобщее одобрение, вступают в силу сетевые эффекты, и популярная технология очень быстро становится доминирующей. На протяжении последних лет сфера применения XML постоянно расширяется, и теперь он используется в качестве базового формата для многих высокоуровневых коммуникационных форматов, включая SOAP (Simple Object Access Protocol — простой протокол доступа к объектам; лежит в основе Web служб), WSDL (Web Service Description Language — язык описания Web служб), XSL (eXtensible Schema Language — расширяемый язык описания схем), RSS (Really Simple Syndication — подлинно простое объединение данных; механизм распространения данных) и многие другие форматы. Некоторые XML-форматы носят универсальный характер, тогда как другие являются специфическими для определенной отрасли или технологии, принятой в компании. В настоящее время при проектировании новых форматов хранения и обмена данными вопрос часто заключается не в том, следует ли использовать XML, а в том, какой уровень абстракции поверх XML следует использовать. Вероятнее всего, установленные на вашем мобильном устройстве приложения, взаимодействующие с сетью, используют для нужд связи, хранения и обмена данными именно XML. Вы можете использовать данные в XML- форматах других систем, но вам также может потребоваться разработка собственных XML-форматов, которые должны будут использовать другие люди. Существуют различные подходы к организации работы с XML-документами, соответствующие различным уровням абстракции. Каждый из них характеризуется своими достоинствами и недостатками. По этим причинам очень важно твердо знать, как работать с XML, чтобы это наилучшим образом отвечало вашим запросам.

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

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

    XML или не XML?

    При всех тех возможностях, которые кроются в XML, легко предположить, что этот язык должен был бы привлекаться всегда, когда требуется осуществлять обмен данными или их хранение. Тем не менее, это не так. Гибкость XML придает ему мощь, но это дается за счет увеличения размера документов. Если требуется осуществить обмен данными сравнительно небольшого объема, то XML великолепно подходит для этой цели. Так, при загрузке 20 строк форматированных записей базы данных размер XML-файла может достигать 20 Кбайт, тогда как при использовании для передачи данных двоичного формата они могут быть сжаты до 2 Кбайт или менее.

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

    Для сравнительно небольших объемов данных использование XML является вполне оправданным, поскольку это позволяет вам воспользоваться при обмене данными всеми преимуществами этого гибкого формата. Однако, что если объем данных увеличится в 10 раз и для выбора варианта проектного решения вам придется отвечать на вопрос: что лучше использовать — 200 Кбайт данных XML или 20 Кбайт двоичных данных? Начиная с таких объемов данных, длительность ожидания пользователем завершения процесса передачи данных между устройством и сервером становится все более заметной, и для принятия взвешенного решения требуется выполнить объективные измерения для каждого варианта реализации.

    Важным фактором, который обязательно должен учитываться, является скорость передачи данных в сетях, используемых вашим мобильным устройством. Для некоторых данных при работе в сетях Wi-Fi проблемы длительности процесса обмена данными вообще не существует, тогда как в случае сетей мобильных телефонов, использующих протокол GRPS, может потребоваться тщательный анализ временных и стоимостных факторов. Если бы объем передаваемых данных был еще на порядок больше и вам пришлось бы выбирать между 2 Мбайт XML-данных и 200 Кбайт двоичных данных, то от вашего решения, какой формат данных использовать, зависело бы еще больше, поскольку теперь уже, скорее всего, задержки на установку соединения будут пренебрежимо малы по сравнению с длительностью фактической передачи данных. И при всем этом нельзя сбрасывать со счетов тот факт, что синтаксический анализ XML-данных потребует, как правило, большего времени по сравнению с анализом двоичных данных, специально оптимизированных под многократные загрузки.

    При небольших объемах данных использование XML обычно не должно вызывать никаких сомнений. С ростом же объема данных необходимо уделять все большее внимание выбору проектного решения, а также измерению объективных временных показателей и тестированию, которые помогут выяснить, перекрывают ли преимущества, обеспечиваемые использованием XML, те дополнительные накладные расходы, которые это за собой влечет. Как и в случае других детализированных форматов, перед передачей XML-документов их можно сжимать, чтобы уменьшить объем передаваемых данных, а после передачи — распаковывать, но это означает дополнительную обработку данных и привязывает сервер и клиента к использованию общего формата сжатия; разумеется, это вполне осуществимо, но не может использоваться в качестве универсального рецепта. Очень важно, чтобы решение принималось вами со знанием дела, на основании тщательно установленных фактов и оценки последствий с точки зрения конечного пользователя. Каждая ситуация имеет свои особенности и определяется запросами пользователей, природой используемых коммуникационных сетей и сравнительной стоимостью передачи двоичных и XML-данных по сетям. Экспериментируйте, почаще измеряйте объективные показатели и принимайте продуманные решения.

    Сравнение XML с другими текстовыми форматами

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

    Различные способы хранения данных в виде текста

    Предположим, что в нашем приложении требуется сохранять некоторые пользовательские данные. Эти данные состоят из трех элементов: идентификационного номера ID, имени и адреса. Приложению требуется сохранять эти данные для собственных нужд, но оно также может передавать их другому приложению. Тремя наиболее распространенными способами хранения таких данных в виде текста являются XML, значения с запятыми в качестве разделителей и значения в виде INI-файлов.

    Сохранение данных в виде XML

    Как и в случае HTML, в XML данные сохраняются в виде текста, заключенного между дескрипторами, которые дополняют передаваемые данные контекстом:

    <UserInfo>

     <UserID> 12 </UserID>

     <UserName> Bob </UserName>

     <UserAddress> Someplace, Somewhere </UserName>

    </UserInfo>

    Следует отметить, что в XML те же данные можно сохранить с использованием атрибутов, например:

    <UserInfo UserID="12" UserName="Bob" UserAddress="Someplace, Somewhere">

    </UserInfo>

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

    Сохранение данных в текстовых файлах с разделителями-запятыми

    Ранее для сохранения данных рассматриваемого типа часто применялись файлы, в которых для разделения элементов данных используются запятые:

    12, Bob, "SomePlace, Somewhere"

    Сохранение данных в INI-файлах

    В прошлом популярным способом сохранения данных были INI-файлы. В INI-файлах данные сохраняются в виде пар "имя-значение":

    [UserInfo]

    UserID=12 UserName=Bob

    UserAddress=Someplace, Somewhere

    Существуют и другие распространенные форматы, например PropertyBag, которые по своим структурным свойствам и гибкости занимают промежуточное положение между XML и INI-файлами и были популярными среди разработчиков на Visual Basic 5 и 6. Что выделяет XML и ставит его выше многих предыдущих форматов — так это дополнительное структурирование данных. Эта структура делает возможным создание иерархических данных без расположения их в определенном порядке. Такой формат оказывается несколько более детализированным, чем многие другие текстовые форматы, но зато и гораздо более гибким. Эта гибкость значительно облегчает учет различий в версиях данных, а также сопровождение и передачу данных между различными системами.

    Иерархическая структура XML-данных

    Очень важно хорошо понимать иерархическую структуру XML. Представляйте себе XML-документ в виде дерева объектов, у каждого из которых могут иметься дополнительные дочерние объекты. Для демонстрации этого изменим приведенный выше пример таким образом, чтобы внести в него дополнительную иерархию:

    <UserInfo>

     <UserID> 12 </UserID>

     <Name>

      <FirstName> Иво </FirstName>

      <LastName> Салмре </LastName>

     </Name>

     <Address>

      <Street>10 НекаяУлица</Street>

      <City>Сиэтл</City>

      <State>WA</State>

     </Address>

    </UserInfo>

    Здесь мы сделали узлы Name и Address подузлами UserInfo.

    Другие возможности XML

    В XML имеется гораздо больше возможностей, чем те, о которых было рассказано выше, включая стандартизованные схемы, типизированные данные и средства проверки действительности документов. В приведенных выше примерах были представлены лишь самые тривиальные образцы фрагментов XML. Хорошее описание всех тонкостей XML вы найдете как в документации .NET Framework, так и, как обычно, в Web. Данная книга и приводимые в ней примеры фокусируют внимание на практических аспектах использования XML на мобильных устройствах и ни в коей мере не могут рассматриваться в качестве исчерпывающего источника информации обо всех возможных сферах применениях XML.

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

    Различные способы работы с XML

    Широкая применимость и всеобщее признание языка XML способствовали его быстрому развитию. Параллельно со становлением языка возникли модели, которые значительно упрощают работу с XML. Как правило, если существуют специализированные API-интерфейсы, ориентированные на XML, то при работе с XML следует избегать использования API-интерфейсов обычного файлового ввода вывода. Достоинством высокоуровневых АРI-интерфейсов является то, что они значительно повышают производительность труда разработчика, перекладывая бремя проектирования и тестирования соответствующих средств на специалистов, чьей единственной задачей было создание высокоэффективных XML-анализаторов. Если вы возьметесь за написание собственного анализатора, то потратите массу времени на решение задачи, которая уже давно решена на множестве самых различных платформ; лучше приложите свои усилия в тех областях, где вы сможете предложить что-то новое.

    Несмотря на существование надежно протестированных высокопроизводительных API-интерфейсов, вам все равно придется принять несколько важных проектных решений, относительно использования XML. Самое важное из них касается того, API-интерфейс какого уровня абстракции следует использовать. Вы должны определиться, будете ли вы работать с низкоуровневым API-интерфейсом XML, допускающим только однонаправленную обработку документов, или с API-интерфейсом XML более высокого уровня, который обеспечивает возможности произвольного доступа с представлением XML-документа в виде дерева в памяти устройства. При работе с XML-данными вы можете использовать один из трех основных подходов: 

    1. Создать собственный "оптимизированный" анализатор с нуля. При наличии ранее разработанных и протестированных методик это почти никогда не стоит делать. Причина, по которой применять такой подход категорически не рекомендуется, заключается в том, что получаемые при этом преимущества лишь в редких случаях окупают усилия, затрачиваемые на разработку и последующее сопровождение соответствующих программ. 

    2. Использовать высокоуровневые универсальные методы синтаксического анализа с произвольным доступом, основанные на модели XML DOM. DOM (Document Object Model — объектная модель документов) обеспечивает возможность работы с XML-данными, хранящимися в памяти в виде иерархического дерева объектов. В результате использования высокоуровневого API-интерфейса для работы с XML вы получаете в высшей степени надежный код, удобный в сопровождении. Такой подход является оптимальным для небольших XML-документов, а также документов, при работе с которыми требуется постоянный произвольный доступ ко всем частям дерева XML документа, или документов, которые должны быть заново целиком сохранены в файле на диске. 

    3. Использовать низкоуровневый API-интерфейс XML, обеспечивающий выполнение лишь однонаправленных операций чтения-записи данных. Применение низкоуровневых API-интерфейсов позволяет максимально повысить производительность, но возлагает дополнительную нагрузку на программистов. Эти API-интерфейсы поддерживают выполнение операций чтения записи данных только в прямом направлении и позволяют считывать или записывать данные XML-дерева в виде потока XML-элементов без сохранения всего документа в памяти. В случае мобильных устройств, для которых память всегда является дефицитным ресурсом, и особенно при работе с большими объемами данных или данными, предназначенными только для чтения, только такой подход и обеспечивает достижение приемлемой производительности. Он представляет собой хорошую основу, являющуюся промежуточной между использованием высокоуровневых АРI-интерфейсов и развертыванием собственной методики. Такой путь является разумным, если привлечение высокоуровневых API-интерфейсов для удовлетворения ваших нужд требует интенсивных дополнительных вычислений и приводит к чрезмерному расходу памяти.

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

    Простой пример, иллюстрирующий применение модели XML DOM и однонаправленного чтения-записи XML-документов

    Ниже мы сравниваем использование высокоуровневой модели DOM и подхода, основанного на использовании однонаправленных операций чтения-записи XML- данных, на примере работы с простыми XML-документами. В обоих случаях генерируется и используется один и тот же XML-документ. Важно подчеркнуть что, ввиду крайней малости объема используемых XML-данных, приемлемую производительность обеспечивают оба подхода. Реальные различия в производительности скажутся лишь при увеличении объема данных. Чтобы представить мысленную картину того, как это могло бы выглядеть, вообразите, что узел данных UserInfo повторен сотни или тысячи раз. При желании вы можете создать файл данных, соответствующий такой ситуации, и использовать его для тестирования своих алгоритмов с целью сравнения результативности обоих подходов. 

    Пример: содержимое XML-файла

    <AllMyData>

     <UserInfo>

      <UserID>14</UserID>

      <Name>

       <FirstName>Иво</FirstName>

       <LastName>Caлмpe</LastName>

      </Name>

     </UserInfo>

    </AllMyData>

    Обращаю ваше внимание на тот факт, что в качестве узла наивысшего уровня я решил использовать не узел UserInfo, а размещенный над ним дополнительный узел. Такая практика поощряется, поскольку XML допускает существование на самом верхнем уровне только одного узла, который называется "корневым" ("root node"). Оставив в качестве корневого узел UserInfo, мы значительно ограничили бы свои возможности в отношении сохранения другой информации наивысшего уровня в файле без пересмотра проекта.

    Использование типового узла наивысшего уровня позволяет свободно добавлять другие узлы нижележащего уровня по мере расширения потребностей. Так, для сохранения важной информации, не зависящей от пользователя, мы могли бы теперь в дополнение к узлу UserInfo ввести узлы ServerInfo и ApplicationInfo. Кроме того, пользователей может быть несколько, и для каждого из них требуется ввести свой узел UserInfo. Описанная выше структура поддерживает включение нескольких разделов UserInfo, следующих один за другим, что было бы невозможным, если бы узел UserInfo был корневым

    XML DOM

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

    Создание дерева объектов в памяти является удобным способом работы с данными среднего объема, которые требуется всего лишь последовательно обновлять. XML-файл размером 20 Кбайт можно довольно быстро загрузить в память и после работы с ним в памяти как с деревом объектов вновь сохранить в файловой системе. Коль скоро объемы интересующих нас данных невелики, модель XML DOM предоставляет отличные возможности для создания XML-документов, обработки их в памяти и вывода XML-данных в файл или сетевой поток.

    Применимость DOM-подхода ограничивается как объемом памяти, доступной для размещения сгенерированного анализатором дерева объектов, так и наличием резервов вычислительной мощности, необходимых для разбора всего дерева XML-данных. Недостатком подхода, основанного на XML DOM, является его монолитность; прежде чем вы сможете получить доступ к XML-данным, вы должны выполнить синтаксический анализ документа и разместить в памяти все содержимое файла или потока. Если вам необходимо работать лишь с небольшим объемом данных, содержащихся в файле большого размера, то доступ к этим данным будет сопряжен с большими накладными расходами.

    Соображения, побуждающие к использованию подхода, основанного на модели XML DOM 

    ■ XML DOM — простая и вместе с тем предлагающая богатые возможности программная модель. Представление XML-документа деревом объектов, хранящимся в памяти, упрощает работу с данными, к которым требуется произвольный доступ. 

    ■ XML DOM отлично подходит для работы с данными небольшого или среднего объема. Коль скоро файл данных имеет достаточно небольшие размеры, его содержимое не займет слишком много места в памяти. 

    ■ XML DOM — наилучший выбор, если необходимо работать (имея возможность вносить изменения) сразу со всеми находящимися в памяти XML-данными. XML DOM является чрезвычайно мощным инструментом, если вашему приложению необходимо работать с данными в режиме произвольного доступа, а данные после их обработки должны быть заново сохранены в файле на диске или потоке.

    Соображения, побуждающие избегать использования подхода, основанного на модели XML DOM 

    ■ Модель программирования XML DOM вынуждает вас выполнять синтаксический анализ и загрузку XML-данных в дерево объектов, хранящееся в памяти, прежде чем вы сможете получить к ним доступ. Слишком расточительно создавать в памяти крупное по размерам дерево всего документа, если вашему приложению требуется доступ лишь к небольшой части входящих в него XML-данных. 

    ■ Использование модели XML DOM приведет к постепенному снижению производительности по мере роста размеров XML-документов. Поскольку в случае крупных файлов многие объекты будут создаваться в условиях ограниченных ресурсов памяти устройства, это иногда может стать причиной нехватки памяти. Кроме того, все созданные объекты впоследствии должны быть удалены из памяти сборщиком мусора, что обременит ваше приложение дополнительными накладными расходами. 

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

    В листинге 10.1 содержится пример кода, предназначенного для чтения и записи представленных выше XML-данных с использованием модели XML DOM.

    Листинг 10.1. Использование XML DOM для сохранения данных в файле и их загрузки

    using System;

    //----------------------------------------------

    //Демонстрирует сохранение и загрузку файлов с

    //использованием объектной модели документов XML

    //----------------------------------------------

    public class SaveAndLoadXML_UseDOM {

     //XML-дескрипторы, которые мы будем использовать в нашем документе

     const string XML_ROOT_TAG = "AllMyData";

     const string XML_USERINFO_TAG = "UserInfo";

     const string XML_USERID_TAG = "UserID";

     const string XML_NAMEINFO_TAG = "Name";

     const string XML_FIRSTNAME_TAG = "FirstName";

     const string XML_LASTNAME_TAG = "LastName";

     //--------------------------------------------------------------

     //Загружает пользовательское состояние

     //

     // [in] fileName: Имя файла, используемого для сохранения данных

     // [out] userId: Загруженный идентификатор пользователя

     // [out] firstName: Загруженное имя пользователя

     // [out] lastName: Загруженная фамилия пользователя

     //--------------------------------------------------------------

     public static void XML_LoadUserInfo(string fileName, out int userId, out string firstName, out string lastName) {

      //Начинаем с нулевых значений

      userId = 0;

      firstName = "";

      lastName = "";

      //Предполагаем, что данные еще не загружены

      bool gotUserInfoData = false;

      System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();

      xmlDocument.Load(fileName);

      //Получить корневой узел

      System.Xml.XmlElement rootElement;

      rootElement = (System.Xml.XmlElement)xmlDocument.ChildNodes[0];

      //Убедиться в том, что корневой узел согласуется с ожидаемым текстом,

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

      if (rootElement.Name != XML_ROOT_TAG) {

       throw new Exception("Тип корневого узла не совпадает с ожидаемым!");

      }

      //-----------------------------------------------------------

      //Простой конечный автомат для итеративного обхода всех узлов

      //-----------------------------------------------------------

      foreach(System.Xml.XmlElement childOf_RootNode in rootElement.ChildNodes) {

       //Если это узел UserInfo, то мы хотим просмотреть его содержимое

       if (childOf_RootNode.Name == XML_USERINFO_TAG) {

        gotUserInfoData = true; //Пользовательские данные найдены


        //--------------------------------

        //Загрузить каждый из подэлементов

        //--------------------------------

        foreach(System.Xml.XmlElement child_UserDataNode in childOf_RootNode.ChildNodes) {

         //Идентификатор пользователя (UserID)

         if (child_UserDataNode.Name == XML_USERID_TAG) {

          userId = System.Convert.ToInt32(child_UserDataNode.InnerText);

         }

         //ФИО пользователя (UserName)

         else if (child_UserDataNode.Name == XML_NAMEINFO_TAG) {

          foreach(System.Xml.XmlElement child_Name in child_UserDataNode.ChildNodes) {

           //Имя (FirstName)

           if (child_Name.Name == XML_FIRSTNAME_TAG) {

            firstName = child_Name.InnerText;
     

           }

           //Фамилия (LastName)

           else if (child_Name.Name == XML_LASTNAME_TAG) {

            lastName = child_Name.InnerText;

           }

          }//Конец цикла разбора UserName

         }//Конец оператора if, осуществляющего проверку UserName

        }//Конец цикла разбора UserInfo

       }// Конец оператора if, осуществляющего проверку UserInfo

      }//Конец цикла разбора корневого узла

      if (gotUserInfoData == false) {

       throw new Exception ("Данные пользователя в XML-документе не найдены!");

      }

     }

     //------------------------------------------------------------------

     //Сохраняет пользовательское состояние

     //

     // [in] fileName: Имя файла, используемого для сохранения данных

     // [in] userId:Идентификатор пользователя, которыймы хотим сохранить

     // [in] firstName: Имя пользователя, которое мы хотим сохранить

     // [in] lastName: Фамилия пользователя, которую мы хотим сохранить

     //------------------------------------------------------------------

     public static void XML_SaveUserInfo(string fileName, int userId, string firstName, string lastName) {

      System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();


      //-----------------------------------------

      //Добавить элемент документа высшего уровня

      //-----------------------------------------

      System.Xml.XmlElement rootNodeForDocument;

      rootNodeForDocument = xmlDocument.CreateElement(XML_ROOT_TAG);

      xmlDocument.AppendChild(rootNodeForDocument);


      //----------------------------------

      //Добавить данные в элемент UserInfo

      //----------------------------------

      System.Xml.XmlElement topNodeForUserData;

      topNodeForUserData = xmlDocument.CreateElement(XML_USERINFO_TAG);

      rootNodeForDocument.AppendChild(topNodeForUserData);


      //---------------------------------------

      //Добавить значение UserID в наш документ

      //---------------------------------------

      //Создать подузел для информации о пространстве имен

      System.Xml.XmlElement subNodeForUserID;

      subNodeForUserID = xmlDocument.CreateElement(XML_USERID_TAG);

      subNodeForUserID.InnerText = System.Convert.ToString(userId);

      //Присоединить подузел UserID к узлу высшего уровня

      topNodeForUserData.AppendChild(subNodeForUserID);


      //---------------------------------------------

      //Добавить все значения NameInfo в наш документ

      //---------------------------------------------

      //Создать подузел для информации о пространстве имен

      System.Xml.XmlElement subNodeForNameInfo;

      subNodeForNameInfo = xmlDocument.CreateElement(XML_NAMEINFO_TAG);


      //Имя (FirstName)

      System.Xml.XmlElement subNodeFirstName;

      subNodeFirstName = xmlDocument.CreateElement(XML_FIRSTNAME_TAG);

      subNodeFirstName.InnerText = firstName;


      //Фамилия (LastName)

      System.Xml.XmlElement subNodeLastName;

      subNodeLastName = xmlDocument.CreateElement(XML_LASTNAME_TAG);

      subNodeLastName.InnerText = lastName;


      //Присоединить подузлы имени и фамилии к родительскому

      //узлу NameInfo

      subNodeForNameInfo.AppendChild(subNodeFirstName);

      subNodeForNameInfo.AppendChild(subNodeLastName);


      //Присоединить подузел NameInfo (вместе с его дочерними узлами)

      //к узлу высшего уровня

      topNodeForUserData.AppendChild(subNodeForNameInfo);


      //------------------

      //Сохранить документ

      //------------------

      try {

       xmlDocument.Save(fileName);

      }

      catch (System.Exception ex) {

       System.Windows.Forms.MessageBox.Show("Ошибка при сохранении XML-документа - " + ex.Message);

      }

     } //Конец функции

    } //Конец класса

    Листинг 10.2. Вызов кода, предназначенного для сохранения и загрузки XML-документа

    private void button1_Click{object sender, System.EventArgs e) {

     const string FILENAME = "TestFileName.XML";

     //Сохранить, используя XML DOM

     SaveAndLoadXML UseDOM.XML_SaveUserInfo(FILENAME, 14, "Ivo", "Salmre");

     //Сохранить, используя объект однонаправленной записи XMLWriter

     //SaveAndLoadXML_UseReaderWriter.XML SaveUserInfo(FILENAME,

     // 18, "Ivo", "Salmre");

     int userID;

     string firstName;

     string lastName;

     //Загрузить, используя XML DOM

     SaveAndLoadXML_UseDOM.XML_LoadUserInfo(FILENAME, out userID, out firstName, out lastName);

     //Загрузить, используя объект однонаправленного чтения XMLReader

     //SaveAndLoadXML_UseReaderWriter.XMILoadUserInfo(FILENAME,

     // out userID, out firstName, out lastName);

     System.Windows.Forms.MessageBox.Show('Готово!" + userID.ToString() + ", " + lastName + ", " + firstName);

    }
     

    Модель однонаправленного чтения-записи XML-данных

    В отличие от подхода XML DOM, обеспечивающего произвольный доступ к XML-данным и интенсивно использующего информацию о состоянии, объекты XMLReader и XMLWriter обеспечивают лишь возможности однонаправленного доступа. Они поддерживают минимальный объем информации о состоянии, которого достаточно для чтения и записи XML-данных, и не пытаются создавать в памяти дерево XML-данных или работать с ним. В этом случае говорят о моделях однонаправленного доступа, поскольку они поддерживают программный курсор, указывающий на текущую позицию в XML-файле, и позволяют работать только с находящимися в этом месте данными; курсор может перемещаться только в прямом направлении, но не в обратном. Объект XMLReader предлагает много возможностей, но в приложениях используется в основном для прохождения узлов XML-документа. При чтении XML-документа XMLReader каждый раз считывает только один узел и связанные с ним атрибуты; это напоминает чтение обычного файла по одной строке за один раз. Когда разработчик заканчивает просмотр узла и его атрибутов, он отдает объекту XMLReader команду перейти к следующему элементу, в результате чего XMLReader сбрасывает содержащуюся в нем информацию, которая относится к содержимому текущего узла. Однонаправленность доступа является необходимой платой за достижение наилучшей производительности и снижение накладных расходов.

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

    Преимущества использования объектов XMLReader и XMLWriter вместо XML DOM коренятся в оптимизации, которая становится возможной либо благодаря тому, что вашему приложению не требуется универсальный синтаксический анализатор, либо благодаря тому, что работу можно выполнить, храня в памяти меньший объем информации о состояния, поскольку вам может не требоваться запись в файл всего XML-дерева, в которое были считаны XML-данные. Если нет нужды в использовании всех богатых функциональных возможностей XML DOM, то XMLReader и XMLWriter позволят добиться лучшей производительности, работая на более низком уровне абстракции.

    Чем XMLReader и XMLWriter отличаются от SAX?

    В .NET Framework и .NET Compact Framework реализован подход, основанный на использовании программного курсора, при котором алгоритмы конечного разработчика отдают объекту XMLReader команды относительно перемещения курсора в прямом направлении и синтаксического анализа очередных элементов XML-данных, однако это не единственный из подходов, в которых используется однонаправленная обработка XML- данных. Другим популярным подходом аналогичного рода является модель SAX (Simple API for XML Model — простой API-интерфейс для работы с XML). В то время как при работе с XMLReader используется подход на основе программного курсора, предоставляющий программисту возможность выбирать, как и когда перемещаться курсору в прямом направлении, SAX представляет собой модель, основанную на событиях, в которой механизм синтаксического анализа выполняет проход по всему XML-документу (также только в прямом направлении) и генерирует события, которые код конечного разработчика может обрабатывать для исследования содержимого XML-документа в ходе его анализа. Модель XMLReader основана на "извлечении" данных, то есть код приложения извлекает очередную порцию XML-данных, которые необходимо обработать. Модель SAX основана на "выталкивании" данных, то есть порции XML-данных передаются событиям, которые обрабатываются кодом приложения. Обе модели преследуют одну и ту же цель, а именно — облегчить быстрое выполнение синтаксического анализа XML-документов при низких накладных расходах. Выбор между моделями SAX и XMLReader/XMLWriter определяется личными предпочтениями и доступностью соответствующих средств на платформе, с которой вы работаете. Приведенные в данном разделе рекомендации в равной степени справедливы для обеих моделей.

    Соображения, побуждающие к использованию однонаправленной обработки XML-данных 

    ■ Такие модели однонаправленного чтения данных, как XMLReader, обеспечивают наиболее быстрые и надежные способы чтения XML-данных даже в случае гигантских файлов. Минимальным требованием является поддержка каркасом информации о состоянии в процессе выполнения синтаксического анализа XML-документа. Объем этой информации не растет с увеличением размера анализируемого XML-документа, и поэтому ограничения на размеры XML-документов, которые вы хотите просматривать для извлечения необходимых данных, практически отсутствуют. Единственным долговременным генерируемым состоянием являются объекты, которые создаются вашим приложением, исходя из нужд анализа. 

    ■ Такие модели однонаправленной записи данных, как модель XMLWriter, обеспечивают наиболее быстрые и простые способы записи корректно сформированных XML-документов. Коды для записи XML-данных при помощи объекта XMLWriter работают быстро и отличаются простотой. Даже в случае сложных XML-документов ваш код, реализующий навигацию между вашими собственными внутренними структурами данных, скорее всего, окажется более сложным, чем код, с помощью которого осуществляется запись XML-данных из памяти. Использовать для вывода XML-дескрипторов объект XMLWriter для гораздо проще, чем самостоятельно написать предназначенный для этого пользовательский код. Существует довольно мало причин, если таковые вообще находятся, по которым следовало бы поступать иначе. 

    ■ Модели однонаправленной обработки прекрасно подходят для извлечения определенных данных или записи коротких потоков XML-данных. Если вас интересует извлечение из XML-документа только определенных данных и вам известно, где именно в иерархии данных файла они находятся, то использование объекта XMLReader и собственного конечного автомата для перехода к нужным данным не вызывает особых затруднений. Аналогичным образом, если вам заранее известно, каким должен быть формат XML-данных, выводимых для записи, работа с объектом XMLWriter не будет для вас сложной.

    Соображения, побуждающие избегать использования однонаправленной обработки XML-данных 

    ■ Модели однонаправленной обработки данных не поддерживают произвольный доступ к элементам документа. Вам дается только один "выстрел", чтобы успеть сделать что-либо с данными по мере их чтения. Если ваш алгоритм нуждается в динамическом перекрестном использовании данных или внесении взаимосвязанных изменений в данные, относящиеся к различным частям XML-документа, то для этого вам придется самостоятельно написать довольно сложный код, интенсивно использующий информацию о состоянии. Поскольку модель XML DOM поддерживает хранящееся в памяти дерево документа, она позволяет легко совершать обход этого дерева для поиска нужных узлов и внесения необходимых изменений. 

    ■ Модели однонаправленной обработки данных требуют выполнения значительного объема работы для реконструкции всей структуры дерева. Если вы хотите вывести для записи тот же самый документ, который был считан, то вам придется продублировать значительную часть той функциональности XML DOM, при помощи которой это можно было бы сделать. Объекты XMLReader отлично приспособлены для извлечения определенных порций данных. Объекты XMLWriter отлично приспособлены для быстрого вывода вашим приложением определенных элементов XML-данных. Если же вам необходимо считать XML-документ и внести в него значительные изменения перед тем, как записать его обратно, то ваш друг — DOM. 

    ■ Модели однонаправленной обработки требуют использования более сложных программных моделей, реализующих навигацию и операции поиска в сложных документах. Написание кода универсального синтаксического анализатора, который работал бы с произвольными иерархиями XML, может вызывать большие трудности. Чтобы найти искомую информацию, вам придется использовать очень сложное состояние, позволяющее определять, в каком узле дерева документа вы находитесь. Так, если вы осуществляете поиск дескриптора <Name>, находящегося внутри определенного дескриптора <Customer>, и в вашем XML-документе имеются дескрипторы <Name>, соответствующие объектам <Customer>, <Employee> и <Vendor>, которые могут присутствовать в XML-дереве на иерархических уровнях различной глубины, то для того, чтобы иметь возможность различать эти случаи и тем caмым гарантировать, что вы получаете корректную информацию, вам придется написать код, отслеживающий, в каком месте документа в настоящее время осуществляется просмотр. Если документ следует единственной корректно- определенной схеме, то, возможно, это не так уж плохо. С другой стороны, если документ может быть подготовлен с использованием одной из нескольких возможных схем, то задача становится алгоритмически сложной. В случае особо сложных документов следует рассмотреть вариант выполнения обработки на сервере, ибо там предоставляются не только более мощные вычислительные возможности, но и более мощные API-интерфейсы, предназначенные для проведения поиска в XML-документах (например, XPATH, поддерживающий запросы данных документа).

    Ниже приведен простой код, предназначенный для чтения и записи представленных ранее данных с использованием модели однонаправленной обработки XML- документов с помощью объектов XMLReader и XMLWriter. Особый интерес для вас может представлять конечный автомат, используемый в объекте XMLReader для отслеживания текущего места в документе; заметьте, что даже для столь простого XML-документа, как наш, этот код вовсе не тривиален. В противоположность этому код, предназначенный для вывода XML-документов при помощи объекта XMLWriter, отличается простотой.

    Листинг 10.3. Использование однонаправленного чтения-записи XML-данных для загрузки XML-документа из файла и его сохранения

    using System;

    public class SaveAndLoadXML UseReaderWriter {

     //XML-дескрипторы, которые мы будем использовать в своем документе

     const string XML_ROOT_TAG = "AllMyData";

     const string XML_USERINFO_TAG = "UserInfo";

     const string XMI_USERID_TAG = "UserID";

     const string XML_NAMEINFO_TAG = "Name";

     const string XML_FIRSTNAME_TAG = "FirstName";

     const string XML_LASTNAME TAG = "LastName";

     //Набор состояний, отслеживаемых по мере чтения данных

     private enum ReadLocation {

      inAllMyData,

      inUserInfo,

      inUserID,

      inName,

      inFirstName,

      inLastName,

     }

     //--------------------------------------------------------------------

     //Сохраняет пользовательское состояние

     //

     // [in] fileName: Имя файла, используемого для сохранения данных

     // [in] userId: Идентификатор пользователя, который мы хотим сохранить

     // [in] firstName: Имя пользователя, которое мы хотим сохранить

     // [in] lastName: Фамилия пользователя, которую мы хотим сохранить

     //--------------------------------------------------------------------

     public static void XML_SaveUserInfo(string fileName, int userId,string firstName, string lastName) {

      System.Xml.XmlTextWriter xmlTextWriter;

      xmlTextWriter =new System.Xml.XmlTextWriter(fileName, System.Text.Encoding.Default);


      //Записать содержимое документа!

      //<Root>

      xmlTextWriter.WriteStartElement(XML_ROOT_TAG);

      //<Root>

      xmlTextWriter.WriteStartElement(XML_USERINFO_TAG);

      //<Root><UserID>

      //<Root><UserInfo>

      xmlTextWriter.WriteStartElement(XML_NAMEINFO_TAG);

      //<Root><UserInfo><Name>

      xmlTextWriter.WriteStartElement(XML_FIRSTNAME_TAG);

      //<Root><UserInfo><Name><FirstName>

      xmlTextWriter.WriteString(firstName); //Запись значения

      xmlTextWriter.WriteEndElement(); //Закрыть дескриптор имени

      //<Root><UserInfo><Name>

      xmlTextWriter.WriteStartElement(XML_LASTNAME_TAG);

      //<Root><UserInfo><Name><LastName>

      xmlTextWriter.WriteString(lastName); //Запись значения

      xmlTextWriter.WriteEndElement(); //Закрыть дескриптор фамилии

      //<Root><UserInfo><Name>

      xmlTextWriter.WriteEndElement(); //Закрыть дескриптор ФИО

      //<Root><UserInfo>

      //<Root><UserInfo>

      xmlTextWriter.WriteStartElement(XML_USERID_TAG);

      //<Root><UserInfo><UserID>

      //Запись значения

      xmlTextWriter.WriteString(userId.ToString());

      xmlTextWriter.WriteEndElement();

      //Закрыть дескриптор UserID

      //<Root><Userlnfo>

      xmlTextWriter.WriteEndElement(); //Закрыть дескриптор UserInfo

      //<Root>

      xmlTextWriter.WriteEndElement(); //Закрыть дескриптор документа

      //

      xmlTextWriter.Close();

     }


     //--------------------------------------------------------------

     //Загружает пользовательское состояние

     //

     // [in] fileName: Имя файла, используемого для сохранения данных

     // [out] userId: Загруженный идентификатор пользователя

     // [out] firstName: Загруженное имя пользователя

     // [out] lastName: Загруженная фамилия пользователя

     //--------------------------------------------------------------

     public static void XML_LoadUserInfo(string fileName, out int userId, out string firstName,out string lastName) {

      ReadLocation currentReadLocation;

      //Начинаем с нулевых значений

      userId = 0;

      firstName = "";

      lastName = "";

      System.Xml.XmlTextReader xmlReader = new System.Xml.XmlTextReader(fileName);

      xmlReader.WhitespaceHandling = System.Xml.WhitespaceHandling.None;

      bool readSuccess;

      readSuccess = xmlReader.Read();

      if (readSuccess == false) {

       throw new System.Exception("Отсутствуют XML-данные для чтения!");

      }

      //Убедиться в том, что мы распознали корневой дескриптор

      if (xmlReader.Name != XML_ROOT_TAG) {

       throw new System.Exception("Корневой дескриптор отличается от ожидаемого!");

      }

      //Отметить текущее местоположение в документе

      currentReadLocation = ReadLocation.inAllMyData;

      //------------------------------------------------------

      //Цикл прохождения документа и чтение необходимых данных

      //------------------------------------------------------

      while (readSuccess) {

       switch (xmlReader.NodeType) {

       //Вызывается при входе в новый элемент

       case System.Xml.XmlNodeType.Element: {

        string nodeName = xmlReader.Name;

        LoadHelper_NewElementEncountered(nodeName, ref currentReadLocation);

        break;

       }

       //----------------------------------------------------

       //Здесь мы можем извлечь некоторый фактический текст и

       //получить данные, которые пытаемся загрузить

       //----------------------------------------------------

       case System.Xml.XmlNodeType.Text: {

        switch (currentReadLocation) {

        case ReadLocation.inFirstName: {

         firstName = xmlReader.Value;

         break;

        }

        case ReadLocation.inLastName: {

         lastName = xmlReader.Value;

         break;

        }

        case ReadLocation.inUserID: {

         userId = System.Convert.ToInt32(xmlReader.Value);

         break;

        }

        }

        break;

       }

       //-------------------------------------------------------------

       //Вызывается, когда встречается конец

       //элемента

       //

       //Мы можем захотеть переключить состояние в зависимости от вида

       //покидаемого узла, чтобы указать на то, что собираемся

       //вернуться назад к его предку

       //-------------------------------------------------------------

       case System.Xml.XmlNodeType.EndElement: {

        bool continueParsing;

        continueParsing = LoadHelper_EndElementEncountered(ref currentReadLocation);

        if (continueParsing ==false) {

         goto finished_reading_wanted_data;

        }

        break;

       }

       default: {

        //He страшно, если имеются XML-узлы других типов, но

        //в нашем примере работы с XML-документом мы должны

        //оповестить об этом факте...

        System.Windows.Forms.MessageBox.Show("Встретился непредвиденный XML-тип " + xmlReader.Name);

        break;

       }

       } //Конец оператора Case, используемого для определения текущего

       //типа XML-элeмeнтa, oбpaбaтывaeмoгo анализатором


       //Перейти к следующему узлу

       readSuccess = xmlReader.Read();

      }

      //Если мы оказались в этом месте программы, не покинув

      //XML-дескриптора UserInfo, то с XML-данными, которые

      //мы считываем, что-то не так

      throw new Exception("He найден элемент UserInfo в XML-документе!");

    finished_reading_wanted_data:

      //Закрыть файл, поскольку работа с ним закончена!

      xmlReader.Close();

     }


     //--------------------------------------------------------

     //Вспомогательный код, ответственный за принятие решения

     //относительно того, в какое состояние необходимо перейти,

     //когда встречается закрывающий дескриптор

     //--------------------------------------------------------

     private static bool LoadHelper_EndElementEncountered(ref ReadLocation currentReadLocation) {

      switch (currentReadLocation) {

      //Если мы покидаем узел Name, то должны вернуться

      //обратно в узел UserInfo

      case ReadLocation.inName: {

       currentReadLocation = ReadLocation.inUserInfo;

       break;

      }

      //Если мы покидаем узел FirstName, то должны вернуться

      //обратно в узел Name

      case ReadLocation.inFirstName: {

       currentReadLocation = ReadLocation.inName;

       break;

      }

      //Если мы покидаем узел LastName, то должны вернуться

      //обратно в узел Name

      case ReadLocation.inLastName: {

       currentReadLocation = ReadLocation.inName;

       break;

      }

      //Если мы покидаем узел UserID, то должны вернуться

      //обратно в узел UserInfo

      case ReadLocation.inUserID: {

       currentReadLocation = ReadLocation.inUserInfo;

       break;

      }

      //Если мы покидаем узел UserInfo, то мы только что

      //закончили чтение данных в узлах UserID, FirstName

      //и LastName.

      //

      //Можно выйти из цикла, поскольку у нас уже есть вся

      //информация, которую мы хотели получить!

      case ReadLocation.inUserInfo: {

       return false; //Анализ должен быть прекращен

      }

      }

      return true; //Продолжить анализ

     }


     private static void LoadHelper_NewElementEncountered(string nodeName,ref ReadLocation currentReadLocation) {

      //------------------------------------------------------

      //Мы вошли в новый элемент!

      //

      //B какое состояние переход возможен, зависит от того, в

      //каком состоянии мы находимся в данный момент

      //------------------------------------------------------

      switch (currentReadLocation) {

      //Если мы находимся в узле AllMyData, то переход возможен

      //в узлы, которые указаны ниже

      case (ReadLocation.inAllMyData): {

       if (nodeName == XMI_USERINFO_TAG) {

        currentReadLocation = ReadLocation.inUserInfo;

       }

       break;

      }

      //Если мы находимся в узле UserInfo, то переход возможен

      //в узлы, которые указаны ниже

      case (ReadLocation.inUserInfo): {

       if (nodeName == XML_USERID_TAG) {

        currentReadLocation = ReadLocation.inUserID;

       } else if (nodeName == XML_NAMEINFO_TAG) {

        currentReadLocation = ReadLocation.inName;

       }

       break;

      }

      //Если мы находимся в узле Name, то переход возможен

      //в узлы, которые указаны ниже

      case (ReadLocation.inName): {

       if (nodeName == XML_FIRSTNAME_TAG) {

        currentReadLocation = ReadLocation.inFirstName;

       } else if (nodeName == XML_LASTNAME_TAG) {

        currentReadLocation = ReadLocation.inLastName;

       }

       break;

      }

      }

     } //Конец функции

    } //Конец класса

    Повышение производительности приложения перекладыванием работы на другие программы

    Разработчики уделяют огромное внимание поиску реализаций алгоритма, которые позволяют добиться максимального быстродействия. А вот о том, стоит ли вообще выполнять данную работу на мобильном устройстве, они чаще всего не задумываются. Во многих случаях некоторая работа может быть выполнена еще до того, как данные поступят на устройство, или переложена на сервер и выполнена в ответ на запрос. Располагая большими объемами доступной памяти, мощными процессорами и накопителями, серверы могут с успехом выполнять значительную часть необходимой предварительной работы, а также обработку по требованию, что можно использовать с выгодой для нужд мобильных приложений.

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

    Избегайте выполнения сложных преобразований данных на устройстве

    Во многих случаях XML-данные удобно преобразовать к другому виду, облегчающему их непосредственный просмотр пользователем. В качестве простого примера можно привести заполнение элементов управления ListBox или ListView данными из XML-документа. Более сложным примером является генерация HTML документов на основе XML-данных. В каждом из этих случаев XML-данные подвергаются определенному преобразованию, позволяющему представить их в удобочитаемом виде. Преобразования часто имеют сложную природу и требуют больших затрат процессорного времени. Старайтесь находить способы, позволяющие выполнять как можно больший объем такой работы на сервере еще до того, как данные попадут на устройство. Чем больший объем трудоемких преобразований будет выполнен на сервере, тем меньшая нагрузка будет возлагаться на устройство

    Если данные, считываемые из базы данных, нуждаются в тех или иных преобразованиях, рассмотрите возможность использования промежуточной Web-службы, развернутой на сервере, в задачи которой будет входить преобразование данных до отправки их на устройство.

    Избегайте выполнения сложного поиска данных на устройстве

    Другой типичной задачей, которую часто приходится решать в приложениях, является поиск данных в ответ на запрос определенной информации. С задачами поиска, фильтрации и сортировки данных приходится иметь дело в большинстве приложений, работающих с данными. Возможные варианты поиска укладываются в диапазон, охватывающий как самые простые схемы поиска, так и сложнейшие методы просмотра данных. Точно так же, как и в случае преобразования данных, предварительное выполнение поиска, организация и фильтрация данных с целью придания им более удобных для доступа форм будут способствовать значительному улучшению производительности приложения. Если вы собираетесь загружать с сервера XML-документы, в которых будет производиться поиск определенной информации, рассмотрите возможность заблаговременного проведения поиска на сервере с тем, чтобы загружать лишь результаты этого поиска; благодаря этому вы сможете сократить длительность обработки данных на устройстве и уменьшить объем данных, подлежащих загрузке.

    Рассмотрите возможность исключения необязательной информации перед отправкой данных на устройство

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

    Когда не стоит перекладывать выполнение работы на сервер

    Очень важно, чтобы вы понимали, в каких случаях выполнение некоторой работы лучше переложить на сервер, но не менее важно, чтобы вы умели различать и случаи, когда так поступать не стоит. В настоящее время ведется очень много разговоров о распределенных вычислениях, которые предполагают выталкивание работы любого рода на другие устройства в сети. Сама по себе эта идея весьма привлекательна, но практическая ее реализация сопряжена с большими трудностями. Как правило, выталкивать работу с устройства на сервер для немедленного выполнения не стоит. Если только подлежащие обработке данные не отличаются высокой плотностью и не требуют выполнения трудоемкого анализа, вам не удастся избежать связанных с этим лишних затрат времени, неудобств, необходимости заботиться о надежности соединений, а также возможных дополнительных расходов на двусторонний обмен данными через сеть. Выталкивание данных с устройства на сервер для немедленной обработки может быть оправданным, например, в случае анализа сложных изображений, когда такие данные, как результаты аэрофотосъемки или медицинские снимки, полученные с использованием камеры высокого разрешения, требуют проведения трудоемкого с вычислительной точки зрения алгоритмического анализа. В подобных ситуациях обмен данными между сервером и устройством оказывает на производительность приложения пренебрежимо малое влияние по сравнению с необходимой обработкой; в этом случае задержки, обусловленные пересылкой данных, компенсируются выигрышем в скорости обработки данных на более мощном оборудовании. При этом длительность обработки данных на устройстве должна сравниваться с суммарным временем задержки, связанной с пересылкой данных на сервер, и длительностью их обработки на сервере с учетом того, что сервер не всегда будет доступным тогда, когда это требуется устройству. В случае XML-документов выталкивание данных с устройства на сервер обычно не оправдывает себя; отношение объема интересующих нас данных к размеру документа является, как правило, не очень высоким, а необходимый анализ не представляет особых сложностей. Кроме того, необходимость поддержания постоянного соединения устройства с сетью в процессе обработки данных на сервере снижает привлекательность такого подхода для мобильных приложений.

    Почему в версии 1.1 .NET Compact Framework не поддерживаются XSLT и XPath?

    При проектировании .NET Compact Framework ставилась цель найти разумный компромисс между двумя проектными ограничениями. Необходимость сведения к минимуму размера NET Compact Framework (объем установленного на устройстве программного обеспечения не должен был превышать 2 Мбайт) вступала в противоречие со стремлением предоставить разработчикам как можно более широкие функциональные возможности. В процессе поиска компромиссных решений степень полезности тех или иных средств и необходимость в них тщательно взвешивались с точки зрения соответствующего увеличения размера .NET Compact Framework. Исходя из этих соображений и было решено, что в первом выпуске NET Compact Framework средства XPath и XSLT поддерживаться не будут.

    XPath — это язык запросов, используемый для проведения поиска в XML-документах. Этот язык предоставляет очень широкие возможности поиска, но отличается сложностью, и для его эффективного использования требуется значительная вычислительная мощность. XSLT — это технология преобразования дерева XML-документа в новый документ в соответствии с определенными правилами; эту технологию часто применяют для преобразования XML-данных в HTML-документы. Для его эффективного функционирования также требуются значительные вычислительные ресурсы.

    Полезность обоих указанных средств совершенно очевидна, и каждому разработчику хотелось бы иметь их в своем распоряжении, но было ли бы уместным их применение в случае мобильных приложений, выполняющихся на устройствах в условиях дефицита ресурсов? Поддержка XSLT и XPath лишь привела бы к напрасному увеличению размера .NET Compact Framework, поскольку предоставляемые разработчику функциональные возможности не могли бы эффективно использоваться во многих задачах, для которых они предназначены. Именно из этих соображений и было решено не включать поддержку XPath и XSLT в версию 1.1 .NET Compact Framework.

    Не исключено, что поддержка этих средств появится в последующих версиях .NET Compact Framework; в частности, существует настоятельная потребность в поддержке XPath. Однако разработчикам следует хорошенько подумать о том, с какими трудностями им придется столкнуться, если они решатся на использование пусть и ценных, но весьма требовательных в отношении необходимых вычислительных ресурсов библиотек. Обычно считается, что встроенные средства среды выполнения должны нормально функционировать при любых обстоятельствах, однако это далеко не так. Вспомните данные ранее в этой главе рекомендации относительно необходимости тщательно взвешивать достоинства и недостатки удобного, но требующего использования обширной информации о состоянии подхода, основанного на модели XML DOM, и более сложного, но менее зависимого от состояния подхода, основанного на однонаправленном доступе к данным с помощью объектов XMLReader и XMLWriter; руководствуйтесь этими же советами и тогда, когда возникает проблема выбора зависящей от состояния или требовательной к ресурсам библиотеки. Вы можете использовать такую библиотеку, но всегда оценивайте, с какими дополнительными расходами это будет сопряжено, и проводите соответствующие измерения.

    Резюме 

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

    Одним из важнейших высокоуровневых проектных решений является решение относительно того, какой формат данных следует выбрать для конкретной коммуникационной задачи — XML или двоичный формат. Применение XML сулит значительные преимущества, но эти преимущества даются за счет увеличения размеров приложений и повышения требований к доступным на устройстве ресурсам. Во многих случаях дополнительные накладные расходы вполне окупаются достигаемыми преимуществами, а хорошая проработка проекта может обеспечить приемлемое функционирование устройства. В то же время, в случае данных большого объема или при работе с узкополосными соединениями следует рассматривать в качестве альтернативного решения двоичные форматы. Наиболее оптимальный подход — это количественная оценка эффектов использования бинарных форматов и XML в реальных ситуациях и принятие проектных решений, исходя из необходимости создания наиболее комфортных условий работы для конечного пользователя. Если проектными решениями и настройкой приложения добиться эффективного функционирования варианта реализации, основанного на использовании XML, не удается, то может потребоваться использование двоичных форматов или внесение изменений в коммуникационную модель.

    При работе с XML очень важно учитывать объем обрабатываемых данных и специфику их назначения. В случае небольших ХМL-документов (например, размером 20 Кбайт) часто оказывается удобным подход, основанный на модели XML DOM, в котором предполагается загрузка в память всего XML-дерева. Модель XML DOM обеспечивает произвольный доступ к данным документа и упрощает обратный вывод документа для его записи на накопитель или в поток. Существенным недостатком модели XML DOM является загрузка в память одновременная всех XML-данных, что делает эту модель в высшей степени зависимой от состояния. При работе с крупными документами этот недостаток может иметь критическое значение.

    Разумной низкоуровневой альтернативой при работе с крупными XML-документами являются XML-библиотеки функций, предназначенных для однонаправленной обработки данных. В .NET Compact Framework предлагаются классы XMLReader и XMLWRiter, тогда как в других средах выполнения для однонаправленного доступа к XML-данным могут предоставляться средства модели SAX. Указанный подход позволяет добиться максимально возможной производительности, поскольку соответствующие средства зависят от состояния в меньшей степени и поэтому не нуждаются в загрузке в память дерева данных, представляющего документ. В случае сложных документов осложняется и работа с использованием объектов XMLReader; для отслеживания текущей позиции в иерархии документа может оказаться полезным подход, основанный на использовании конечных автоматов. Объекты XMLWriter упрощают вывод XML-данных с целью их записи в файл. При работе с большими объемами XML- данных на мобильных устройствах использование модели однонаправленной обработки данных может оказаться единственно разумным подходом.

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

    Если ваше приложение нуждается в хранении данных, обмене данными или подключении к сетевым источникам информации, то вполне вероятно, что, в конечном счете, вы используете XML в той или иной форме. Преимущества стандартизованного текстового формата делают его привлекательным для использования в самых различных областях применения. Однако даже после того, как вы примете решение использовать XML, в вашем распоряжении останется масса дополнительных степеней свободы в отношении того, как именно следует организовать работу с XML в приложении. Разделение труда между серверами и мобильными устройствами, уровень абстракции и степень зависимости используемых вами АРI-интерфейсов от состояния, а также модель обработки, используемая для работы с XML, — все это оказывает огромное влияние на то, как будет оценено качество приложения конечным пользователем. Важно хорошо понимать необходимость выбора тех или иных решений, видеть их относительные достоинства и недостатки и непрерывно экспериментировать в поиске наиболее оптимального способа использования XML в приложении.







     


    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх