Windows Script Host для Windows 2000/XP

Попов Андрей Владимирович

Глава 6

Практическая работа с данными в XML-файлах

 

 

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

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

□ межплатформенный обмен данными между системами разных разработчиков;

□ сбор данных из подразделений организации;

□ обмен коммерческими документами между предприятиями;

□ сбор отчетности государственными органами.

Сейчас библиотеки для работы с XML созданы практически для всех популярных систем разработки приложений и систем управления базами данных. При использовании сценариев WSH также нет необходимости писать собственные программы для разбора XML-формата (такие программы называются парсерами), т.к. встроенный в Windows браузер Internet Explorer версии 4.01 и выше имеет в своем составе в качестве СОМ-объекта парсер MSXML — Microsoft XML library. В настоящей главе для простоты и краткости изложения мы будем пользоваться лишь двумя объектными моделями, которые предоставляет MSXML, не затрагивая рассмотрение таких специфических для XML-файлов понятий, как определения DTD — Documents Type Definitions, используемые для описания и проверки структуры XML-документа, или стилевые таблицы XSL — Extensible Stylesheet Language, предназначенные для формирования на основе данных из XML-источника страницы HTML.

 

Записная книжка в формате XML

В предыдущей главе мы рассматривали сценарий для работы с записной книжкой, которая хранится в простом текстовом файле book.txt с разделителями. Каждая строка этого файла содержала одну запись в формате Фамилия|Имя|Телефон|Улица|Дом|Кв.|Примечание:

Потапов|Сергей|55-55-55|Моховая|3|10|Без примечаний

Попов|Андрей|56-56-56|Ленина|3|5|Без примечаний

Иванов|Иван|17-17-17|Садовая|4|6|Очень хороший человек

Казаков|Сергей|24-19-68|Полежаева|101|22|Тоже очень хороший человек

Для преобразования файла book.txt к формату XML мы введем теги, описанные в табл. 6.1.

Таблица 6.1. Описание тегов для записной книжки в XML-формате

Тег Значение
<PhoneList> Корневой тег, обозначает начало записной книжки
<Person> Обозначает начало новой записи в книжке
<LastName> Фамилия человека
<Name> Имя
<Phone> Телефон
<Street> Улица
<House> Дом
<App> Квартира
<Note> Замечания

Иерархия элементов из таблицы 6.1 показана в листинге 6.1.

Листинг 6.1. Иерархия XML-элементов для записной книжки

 

  Фамилия

  Имя

  Телефон

  Улица

  Дом

  Квартира

  Примечание

 

 Другие записи

Файл book.xml для записной книжки формируется в соответствии с листингом 6.1 (листинг 6.2)

Листинг 6.2. Содержимое файла book.xml

 

 

  Потапов

  Сергей

  55-55-55

  Моховая

  3

  10

  Без примечаний

 

 

  Попов

  Андрей

  56-56-56

  Ленина

  3

  5

  Без примечаний

 

 

  Иванов

  Иван

  17-17-17

  Садовая

  4

  6

  Очень хороший человек

 

 

  Казаков

  Сергей

  24-19-68

  Полежаева

  101

  22

  Тоже очень хороший человек

 

 

 

Просмотр XML-файла с помощью объектной модели Internet Explorer 4.0

 

Если требуется только просматривать и анализировать XML-файл, не модифицируя его, то проще всего воспользоваться объектной моделью MSXML, реализованной в Internet Explorer 4.01.

Замечание

Как отмечено в документации MSDN, эта объектная модель является устаревшей и должна быть заменена моделью XML DOM ( XML Document Object Model ), которая является стандартом корпорации W3C. Однако последняя на момент написания книги версия Internet Explorer 6.0 поддерживает обе эти модели для разбора XML-файлов.

 

Описание объектной модели

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

Для анализа содержимого XML-файла используются три объекта: XML Document (объект для работы с XML-документом в целом), XML Element (отвечает за работу с каждым из элементов XML-файла) и Element Collection (коллекция XML-элементов, доступ к которым при помощи метода item() возможен по имени или порядковому номеру).

Полный набор свойств и методов этих трех объектов мы рассматривать не будем; в табл. 6.2 и 6.3 приведено описание нескольких основных свойств объектов XML Document и XML Element, некоторые из них понадобятся нам в дальнейшем при составлении сценария на языке JScript для просмотра записной книжки.

Таблица 6.2. Свойства объекта XML Document

Свойство Описание
URL Задает или возвращает путь к обрабатываемому документу
root Содержит корневой элемент XML-документа, Свойство доступно только для чтения
charset Возвращает или устанавливает название текущей кодировочной таблицы
version Содержит номер версии XML. Свойство доступно только для чтения

Таблица 6.3. Свойства объекта XML Element

Свойство Описание
children Содержит коллекцию дочерних элементов
tagName Содержит имя тега. Свойство доступно для чтения и записи
text Возвращает текстовое содержимое элементов и комментариев
parent Возвращает указатель на родительский элемент. Ссылки на родительский элемент имеют все элементы, за исключением корневого
type Возвращает тип элемента: 0 — элемент, 1 — текст, 2 — комментарий, 3 — Document, 4 — DTD

 

Пример сценария

С помощью приведенного ниже сценария SortNameMSXML.js все записи из book.xml сортируются по фамилии и отображаются в Блокноте. Напомним, что аналогичную задачу для текстового файла с разделителями book.txt реализует сценарий SortName.js, приведенный в листинге 5.21. Алгоритм работы сценария SortNameMSXML.js, как и SortName.js, сводится к следующим основным шагам.

1. Информация из файла book.xml считывается в массив PersonArr. Каждый элемент массива является экземпляром объекта Person, в котором хранятся все данные для одного человека.

2. Массив PersonArr сортируется по возрастанию фамилий.

3. Содержимое всех записей из массива PersonArr выводится в текстовый файл out.txt.

4. Файл out.txt открывается в Блокноте.

Таким образом, специфика работы с XML-файлом проявляется лишь при считывании данных из файла book.xml в массив PersonArr. Для этого используется функция FileToArray(). Сначала в этой функции создается пустой массив PersonArr и экземпляр XML объекта XML Document:

PersonArr=new Array();

XML=WScript.CreateObject("MSXML");

В свойство url объекта XML записывается путь к файлу book.xml, который хранится в переменной PathBook:

XML.url=PathBook;

Далее в функции FileToArray о определяется количество элементов , т.е. количество записей в книжке (переменная NomRec):

NamRec=XML.root.children.item("Person").length;

В цикле for происходит перебор всех элементов , которые являются элементами соответствующей коллекции:

//Перебираем коллекцию XML-элементов Person

for (i=0; i

 //Выделяем в коллекции XML-элементов i-й элемент Person

 XItem=XML.root.children.item("Person", i);

 //Добавляем новый элемент, в массив объектов Person

 PersonToArray(XItem);

}

Как мы видим, каждый элемент передается в качестве аргумента в функцию PersonToArray( XItem ) , в которой создается новый экземпляр PersonRec объекта Person, заполняются поля этого объекта и происходит добавление PersonRec в массив PersonArr:

function PersonToArray(XItem) {

 //Создаем новый экземпляр PersonRec объекта Person

 PersonRec=new Person();

 //Заполняем поля объекта PersonRec

 PersonRec.LastName=GetTagVal(XItem,"LastName");

 PersonRec.Name=GetTagVal(XItem,"Name");

 PersonRec.Phone=GetTagVal(XItem,"Phone");

 PersonRec.Street=GetTagVal(XItem,"Street");

 PersonRec.House=GetTagVal(XItem,"House");

 PersonRec.App=GetTagVal(XItem,"App");

 PersonRec.Note=GetTagVal(XItem,"Note");

 //Сохраняем объект PersonRec в массиве

 PersonArr[PersonArr.length]=PersonRec;

}

Поля объекта PersonRec заполняются с помощью функции GetTagVal( obj, tgName ) , которая возвращает значение дочернего для элемента obj элемента с именем tgName :

function GetTagVal(obj, tgName) {

 //Возвращаем значение тега tgName

 return obj.Children.Item(tgName,0).Text;

}

В листинге 6.3 приводится полный текст сценария SortNameMSXMLjs. 

Листинг 6.3. Чтение данных из XML-файла с помощью объектной модели Internet Explorer 4.0

/*******************************************************************/

/* Имя: SortNameMSXML.js                                           */

/* Язык: JScript                                                   */

/* Описание: Записная книжка (данные в XML-файле book.xml).        */

/*           Вывод всех записей с сортировкой по фамилии с         */

/*           помощью объектной модели Internet Explorer 4.0        */

/*******************************************************************/

//Объявляем переменные

var

 WshShell,FSO,

 BasePath,     //Путь к текущему каталогу

 PathBook,     //Путь к файлу с данными

 PathOut,      //Путь к выходному файлу

 FBook,        //Файл с данными

 FOut,         //Выходной файл

 NomRec=0,     //Счетчик количества записей

 PersonRec,    //Объект для хранения данных об одном человеке

 PersonArr;    //Массив для хранения объектов PersonRec

 ForWriting=2; //Константа для создания выходного файла

//Конструктор объекта Person

function Person(LastName,Name,Phone,Street,House,App,Note) {

 this.LastName=LastName; //Фамилия

 this.Name=Name;         //Имя

 this.Phone=Phone;       //Телефон

 this.Street=Street;     //Улица

 this.House=House;       //Дом

 this.App=App;           //Квартира

 this.Note=Note;         //Примечание

}

//Определение значения тега tgName XML-элемента obj

function GetTagVal(obj, tgName) {

 //Возвращаем значение тега tgName

 return obj.Children.Item(tgName,0).Text;

}

//Заполнение нового элемента массива

function PersonToArray(XItem) {

 //Создаем новый экземпляр PersonRec объекта Person

 PersonRec=new Person();

 //Заполняем поля объекта PersonRec

 PersonRec.LastName=GetTagVal(XItem,"LastName");

 PersonRec.Name=GetTagVal(XItem,"Name");

 PersonRec.Phone=GetTagVal(XItem,"Phone");

 PersonRec.Street=GetTagVal(XItem,"Street");

 PersonRec.House=GetTagVal(XItem,"House");

 PersonRec.App=GetTagVal(XItem,"App");

 PersonRec.Note=GetTagVal(XItem,"Note");

 //Сохраняем объект PersonRec в массиве

 PersonArr[PersonArr.length]=PersonRec;

}

//Создание массива объектов Person

function FileToArray() {

var

 XML,NomRec,XItem,ex;

 //Создаем массив PersonArr

 PersonArr=new Array(); 

 //Создаем объект MSXML

 XML=WScript.CreateObject("MSXML");

 //Задаем путь к файлу с данными

 XML.url=PathBook;

 //Инициализируем счетчик числа элементов Person

 //в XML-файле

 NomRec=0;

 try {

  //Определяем число элементов Person в XML-файле

  NomRec=XML.root.children.item("Person").length;

  if (typeof(NomRec)=="undefined") NomRec=1;

 } catch (ex) {

  NomRec=0;

 }

 //Перебираем коллекцию XML-элементов Person

 for (i=0;i

  //Выделяем в коллекции XML-элементов i-й элемент Person

  XItem=XML.root.children.item("Person",i);

  //Добавляем новый элемент в массив объектов Person

  PersonToArray(XItem);

 }

}

//Запись в выходной файл заголовка отчета

function TopReport(Mess) {

 FOut.WriteLine(Mess);

 FOut.WriteLine("--------------------");

 FOut.WriteLine("");

}

//Запись в выходной файл итоговой информации

function BottomReport() {

 FOut.WriteLine("Всего записей: "+NomRec);

}

//Запись данных из объекта Person в выходной файл

function PrintPerson(PersRec) {

 FOut.WriteLine("Фамилия: "+PersRec.LastName);

 FOut.WriteLine("Имя: "+PersRec.Name);

 FOut.WriteLine("Телефон: "+PersRec.Phone);

 FOut.WriteLine("Улица: "+PersRec.Street);

 FOut.WriteLine("Дом: "+PersRec.House);

 FOut.WriteLine("Кв.: "+PersRec.App);

 FOut.WriteLine("Заметки: "+PersRec.Note);

 FOut.WriteLine("*********************************");

 NomRec++;

}

//Сортировка массива и вывод его содержимого в выходной файл

function ListPersonArray() {

var i,a;

 //Сортировка массива по фамилии

 PersonArr.sort(SortLastName);

 //Цикл по всем элементам массива PersonArr

 for (i=0;i<=PersonArr.length-1;i++) {

  //Запись информации в выходной файл

  PrintPerson(PersonArr[i]);

 }

}

//Функция для сортировки массива по фамилии

function SortLastName(Pers1,Pers2) {

 if (Pers1.LastName

 else if (Pers1.LastName==Pers2.LastName) return 0;

 else return 1;

}

//Вывод содержимого файла с данными

function ListFile() {

 //Считывание данных из файла в массив

 FileToArray();

 //Запись информации из массива в выходной файл

 ListPersonArray();

}

//Просмотр содержимого выходного файла в Блокноте

function MakeOut() {

 //Закрываем выходной файл

 FOut.Close();

 //Открываем выходной файл в Блокноте

 WshShell.Run("notepad "+PathOut,1);

}

//Построение путей к файлам

function InitPath() {

 BasePath=WshShell.CurrentDirectory+"\\";

 //Путь к файлу с данными

 PathBook=BasePath+"book.xml",

 //Путь к выходному файлу

 PathOut=BasePath+"out.txt";

}

//Основная запускная функция

function Main() {

 //Создаем объект WshShell

 WshShell = WScript.CreateObject("WScript.Shell");

 //Определяем пути к файлам

 InitPath();

 //Создаем объект FileSystemObject

 FSO=WScript.CreateObject("Scripting.FileSystemObject");

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

 FOut=FSO.OpenTextFile(PathOut,ForWriting,true);

 //Печатаем заголовок отчета

 TopReport("Сортировка по фамилии");

 //Выводим содержимого файла с данными

 ListFile();

 //Печатаем итоговую информацию

 BottomReport("Всего записей: "+PersonArr.length);

 //Открываем выходной файл в Блокноте

 MakeOut();

}

/*******************  Начало  **********************************/

Main();

/*************  Конец *********************************************/

 

Использование XML DOM для просмотра и изменения ХМL-файла

 

Объектная модель XML DOM (XML Document Object Model, объектная модель документа XML) является рекомендованным корпорацией W3C стандартом, который определяет интерфейсы, с помощью которых приложения могут загружать XML-файл, просматривать его содержимое, производить поиск, добавление, изменение и удаление данных, сохранять сделанные изменения в файле. Отметим, что в модели XML DOM документ в формате XML рассматривается как иерархическое дерево, которое состоит из элементов, называемых узлами (nodes), и имеет один корневой элемент (узел).

Замечание

В дальнейшем в этой главе терминами "элемент" и "узел" мы будем пользоваться как синонимами. 

 

Описание модели XML DOM

Парсер MSXML поддерживает много объектов, определяемых в модели XML DOM, с помощью которых можно решать связанные с XML задачи различного уровня сложности. Нам в дальнейшем для написания сценариев, которые осуществляют просмотр записной книжки в XML-формате, а также поиск, добавление и удаление записей из этой книжки, понадобятся только три основных объекта: DOMDocument (представляет XML-документ в целом), XMLDOMNode (представляет одиночный XML-элемент, т. е. один узел в дереве) и XMLDOMNodeList (коллекция элементов, являющихся дочерними по отношению к определенному узлу в дереве, доступ к которым возможен по порядковому номеру при помощи метода item()).

В свою очередь, объекты DOMDocument и XMLDOMNode имеют множество свойств и методов, некоторые из них (включая все свойства и методы, которые используются при написании сценариев для работы с записной книжкой) описаны в табл. 6.4–6.6.

Таблица 6.4. Свойства и методы объекта DOMDocument

Название Тип Описание
childNodes Свойство Содержит коллекцию всех узлов документа. Свойство доступно только для чтения
documentElement Свойство Содержит ссылку на корневой элемент документа. Свойство доступно как для чтения, так и для записи
getElementsByTagName( tagName ) Метод Возвращает коллекцию всех элементов в документе, имеющих имя, которое задается параметром tagName
hasChildNodes() Метод Возвращает true , если в документе есть элементы. В противном случае возвращает false
load(url) Метод Загружает XML-документ из файла, путь к которому задан параметром url
loadXML( xmlString ) Метод Загружает XML-документ, содержимое которого содержится в строке xmlString
url Свойство Содержит путь к загруженному XML-документу. Для того чтобы изменить это свойство, нужно заново загрузить документ с помощью метода load

Таблица 6.5. Свойства объекта XMLDOMNode

Название Описание
attributes Содержит список атрибутов узла. Свойство доступно только для чтения
childNodes Содержит коллекцию всех узлов, которые являются дочерними по отношению к данному узлу. Свойство доступно только для чтения
firstChild Содержит ссылку на первый дочерний узел. Свойство доступно только для чтения
lastChild Содержит ссылку на последний дочерний узел. Свойство доступно только для чтения
nodeName Содержит имя узла. Свойство доступно только для чтения
parentNode Содержит ссылку на родительский узел (для тех узлов, которые имеют родительский элемент). Свойство доступно только для чтения
text Возвращает или устанавливает текстовое содержимое узла

Таблица 6.6. Методы объекта XMLDOMNode

Название Описание
appendChild( NewElem ) Добавляет новый элемент NewElem в качестве последнего дочернего элемента. В качестве результата возвращает ссылку на добавленный узел
cloneNode( deep ) Создает новый узел, который является точной копией текущего узла. Параметр deep — это логическая константа, которая указывает, нужно ли при создании нового узла копировать дочерние узлы текущего элемента ( deep =true) , либо этого делать не следует ( deep =true)
hasChildNodes() Возвращает true , если у узла есть дочерние элементы. В противном случае возвращает false
removeChild( OldElem ) Удаляет дочерний элемент, ссылка на который содержится в параметре OldElem
replaceChild( OldElem, NewElem ) Заменяет элемент, ссылка на который содержится в параметре OldElem , на элемент, ссылка на который содержится в параметре NewElem
selectNodes( patternString ) Производит поиск дочерних элементов, содержимое которых удовлетворяет шаблону поиска patternString . В результате возвращает объект XMLDOMNodeList , содержащий коллекцию всех найденных узлов
selectSingleNode( patternString ) Производит поиск первого дочернего элемента, содержимое которого удовлетворяет шаблону поиска patternString . В случае удачного поиска возвращает ссылку на найденный элемент, в противном случае возвращает Null  

 

Просмотр содержимого записной книжки

Для того чтобы использовать схему XML DOM в сценарии SortNameMSXML.js, осуществляющем вывод информации из XML-файла book.xml в Блокнот, нужно внести изменения в три функции: GetTagVal( obj, tgName ) , PersonToArray( XNode ) и FileToArray(). Сценарий, который получится в результате этих изменений, назовем SortNameXMLDOM.js.

В функции FileToArray() сначала создается пустой массив PersonArr и экземпляр XML объекта DOMDocument:

PersonArr=new Array();

XML = WScript.CreateObject("Msxml.DOMDocument");

Для загрузки содержимого файла book.xml (путь к этому файлу хранится в переменной PathBook) в объект xml, используется метод load:

XML.load(PathBook);

Указатель на корневой элемент записывается в переменную Root с помощью свойства documentElement объекта XML:

Root=XML.documentElement;

После этого нам остается в цикле перебрать все элементы Person (для корневого элемента они являются дочерними элементами первого уровня вложенности) и для каждого из них вызвать функцию PersonToArray():

for (i=1; i<=Root.childNodes.length-1; i++) {

 //Выделяем в коллекции XML-элементов i-й элемент

 //первого уровня вложенности

 CurrNode=Root.childNodes.item(i);

 //Добавляем новый элемент в массив объектов Person

 PersonToArray(CurrNode);

}

Функция PersonToArray( XNode ) в SortNameXMLDOM.js имеет тот же вид, что и в сценарии SortNameMSXML.js:

function PersonToArray(XNode) {

 //Создаем новый экземпляр PersonRec объекта Person

 PersonRec=new Person();

 //Заполняем поля объекта PersonRec

 PersonRec.LastName=GetTagVal(XNode,"LastName");

 PersonRec.Name=GetTagVal(XNode,"Name");

 PersonRec.Phone=GetTagVal(XNode,"Phone");

 PersonRec.Street=GetTagVal(XNode,"Street");

 PersonRec.House=GetTagVal(XNode,"House");

 PersonRec.App=GetTagVal(XNode,"App");

 PersonRec.Note=GetTagVal(XNode,"Note");

 //Сохраняем объект PersonRec в массиве

 PersonArr[PersonArr.length]=PersonRec;

}

Здесь для построения функции GetTagVal( obj, tgName ) , которая возвращает значение дочернего для элемента obj элемента с именем tgName , используется метод getElementsByTagName, возвращающий коллекцию дочерних элементов с заданным именем:

function GetTagVal(obj, tgName) {

 var ElemList;

 //Создаем коллекцию дочерних для obj элементов, которые

 //задаются тегом tgName

 ElemList=obj.getElementsByTagName(tgName);

 //Проверяем, есть ли в коллекции ElemList элементы

 if (ElemList.length>0)

  //Возвращаем значение первого встретившегося элемента tgName

  return ElemList.item(0).text

 else return "";

}

В листинге 6.4 приводится полный текст сценария SortNameXMLDOM.js.

Листинг 6.4. Чтение данных из XML-файла с помощью XML DOM

/*******************************************************************/

/* Имя: SortNameXMLDOM.js                                          */

/* Язык: JScript                                                   */

/* Описание: Записная книжка (данные в XML-файле book.xml).        */

/*           Вывод всех записей с сортировкой по фамилии с         */

/*           помощью объектной модели XML DOM                      */

/*******************************************************************/

//Объявляем переменные

var

 WshShell,FSO,

 BasePath,     //Путь к текущему каталогу

 PathBook,     //Путь к файлу с данными

 PathOut,      //Путь к выходному файлу

 FBook,        //Файл с данными

 FOut,         //Выходной файл

 NomRec=0,     //Счетчик количества записей

 PersonRec,    //Объект для хранения данных об одном человеке

 PersonArr;    //Массив для хранения объектов PersonRec

 ForWriting=2; //Константа для создания выходного файла

//Конструктор объекта Person

function Person(LastName,Name,Phone,Street,House,App,Note) {

 this.LastName=LastName; //Фамилия

 this.Name=Name;         //Имя

 this.Phone=Phone;       //Телефон

 this.Street=Street;     //Улица

 this.House=House;       //Дом

 this.App=App;           //Квартира

 this.Note=Note;         //Примечание

}

//Определение значения тега tgName XML-элемента obj

function GetTagVal(obj, tgName) {

 var ElemList;

 //Создаем коллекцию дочерних для obj элементов, которые

 //задаются тегом tgName

 ElemList=obj.getElementsByTagName(tgName);

 //Проверяем, есть ли в коллекции ElemList элементы

 if (ElemList.length>0)

  //Возвращаем значение первого встретившегося элемента tgName

  return ElemList.item(0).text

 else return "";

}

//Заполнение нового элемента массива

function PersonToArray(XNode) {

 //Создаем новый экземпляр PersonRec объекта Person

 PersonRec=new Person();

 //Заполняем поля объекта PersonRec

 PersonRec.LastName=GetTagVal(XNode,"LastName");

 PersonRec.Name=GetTagVal(XNode,"Name");

 PersonRec.Phone=GetTagVal(XNode,"Phone");

 PersonRec.Street=GetTagVal(XNode,"Street");

 PersonRec.House=GetTagVal(XNode,"House");

 PersonRec.App=GetTagVal(XNode,"App");

 PersonRec.Note=GetTagVal(XNode,"Note");

 //Сохраняем объект PersonRec в массиве

 PersonArr[PersonArr.length]=PersonRec;

}

//Создание массива объектов Person

function FileToArray() {

 var XML,Root,NomRec,CurrNode,ex,i;

 //Создаем массив PersonArr

 PersonArr=new Array();

 //Создаем объект XML DOM

 XML = WScript.CreateObject("Msxml.DOMDocument");

 //Загружаем XML-документ из файла

 XML.load(PathBook);

 //Сохраняем в переменной Root ссылку на корневой элемент документа

 Root=XML.documentElement;

 //Перебираем все дочерние элементы первого уровня вложенности

 //для корневого элемента

 for (i=1; i<=Root.childNodes.length-1;i++) {

  //Выделяем в коллекции XML-элементов i-й элемент

  CurrNode=Root.childNodes.item(i);

  //Добавляем новый элемент в массив объектов Person

  PersonToArray(CurrNode);

 }

}

//Запись в выходной файл заголовка отчета

function TopReport(Mess) {

 FOut.WriteLine(Mess);

 FOut.WriteLine("--------------------");

 FOut.WriteLine("");

}

//Запись в выходной файл итоговой информации

function BottomReport(Mess) {

 FOut.WriteLine(Mess);

}

//Запись данных из объекта Person в выходной файл

function PrintPerson(PersRec) {

 FOut.WriteLine("Фамилия: "+PersRec.LastName);

 FOut.WriteLine("Имя: "+PersRec.Name);

 FOut.WriteLine("Телефон: "+PersRec.Phone);

 FOut.WriteLine("Улица: "+PersRec.Street);

 FOut.WriteLine("Дом: "+PersRec.House);

 FOut.WriteLine("Кв.: "+PersRec.App);

 FOut.WriteLine("Заметки: "+PersRec.Note);

 FOut.WriteLine("*********************************");

 NomRec++;

}

//Сортировка массива и вывод его содержимого в выходной файл

function ListPersonArray() {

 var i;

 //Сортировка массива по фамилии

 PersonArr.sort(SortLastName);

 //Цикл по всем элементам массива PersonArr

 for (i=0;i<=PersonArr.length-1;i++) {

  //Запись информации в выходной файл

  PrintPerson(PersonArr[i]);

 }

}

//Функция для сортировки массива по фамилии

function SortLastName(Pers1,Pers2) {

 if (Pers1.LastName

 else if (Pers1.LastName==Pers2.LastName) return 0;

 else return 1;

}

//Вывод содержимого файла с данными

function ListFile() {

 //Считывание данных из файла в массив

 FileToArray();

 //Запись информации из массива в выходной файл

 ListPersonArray();

}

//Просмотр содержимого выходного файла в Блокноте

function MakeOut() {

 //Закрываем выходной файл

 FOut.Close();

 //Открываем выходной файл в Блокноте

 WshShell.Run("notepad "+PathOut,1);

}

//Построение путей к файлам

function InitPath() {

 BasePath=WshShell.CurrentDirectory+"\\";

 //Путь к файлу с данными

 PathBook=BasePath+"book.xml",

 //Путь к выходному файлу

 PathOut=BasePath+"out.txt";

}

//Основная запускная функция

function Main() {

 //Создаем объект WshShell

 WshShell = WScript.CreateObject("WScript.Shell");

 //Определяем пути к файлам

 InitPath();

 //Создаем объект FileSystemObject

 FSO=WScript.CreateObject("Scripting.FileSystemObject");

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

 FOut=FSO.OpenTextFile(PathOut,ForWriting,true);

 //Печатаем заголовок отчета

 TopReport("Сортировка по фамилии");

 //Выводим содержимого файла с данными

 ListFile();

 //Печатаем итоговую информацию

 BottomReport("Всего записей: "+PersonArr.length);

 //Открываем выходной файл в Блокноте

 MakeOut();

}

/*******************  Начало  **********************************/

Main();

/*************  Конец *********************************************/

 

Добавление информации в записную книжку

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

Для иллюстрации методов XML DOM, позволяющих записывать данные в XML-файл, рассмотрим сценарий AddRecord.js, в котором производится добавление в book.xml следующей записи:

 Сидоров

 Aнтон

 18-18-18

 Саранская

 12

 4

 Запись добавлена из сценария

Процесс добавления записи в книжку осуществляется в функции AddRecord(). Здесь сначала заполняются нужными значениями поля объекта PersonRec (функция MakePersonRec()), а затем данные из PersonRec добавляются в файл book.xml (функция RecordToFile(PersonRec)):

function AddRecord() {

 //Заполняем поля объекта PersonRec

 MakePersonRec();

 //Сохраняем данные из объекта PersonRec в XML-файле

 RecordToFile(PersonRec);

}

Итак, наиболее важной в сценарии является функция RecordToFile( PersonRec ) . В этой функции сначала создается экземпляр XMLDoc объекта DOMDocument и с помощью метода load загружается файл book.xml:

XMLDoc = WScript.CreateObject("Msxml.DOMDocument");

XMLDoc.load(PathBook);

Указатель на корневой элемент сохраняется в переменной Root:

Root=XMLDoc.documentElement;

После этого с помощью метода createElement создается новый элемент Person, который затем добавляется в book.xml (метод appendChild):

//Создаем XML-элемент Person

NewElem=XMLDoc.createElement("Person");

//Добавляем новый элемент в XML-файл

Root.appendChild(NewElem);

Другие добавляемые элементы (LastName, Name, Phone, Street, House, App и Note) должны быть дочерними относительно элемента Person, поэтому в переменной Root мы сохраним ссылку на последний добавленный элемент Person:

Root=Root.lastChild;

Все элементы добавляются с помощью вызовов методов createElement и appendChild, например:

//Создаем элемент LastName

NewElem=XMLDoc.createElement("LastName");

//Добавляем новый элемент в XML-файл (внутри элемента Person)

Root.appendChild(NewElem);

Содержимое добавляемых элементов (свойство text) берется из соответствующих полей объекта PersRec, например:

//Подставляем в качестве содержимого элемента LastName

//значение поля LastName объекта PersRec

Root.lastChild.text=PersRec.LastName;

После того как все нужные элементы добавлены, измененный файл book.xml с помощью метода save сохраняется на жестком диске:

XMLDoc.save(PathBook);

Полный текст сценария AddRecord.js приводится в листинге 6.5.

Листинг 6.5. Добавление данных в XML-файл с помощью XML DOM

/*******************************************************************/

/* Имя: AddRecord.js                                               */

/* Язык: JScript                                                   */

/* Описание: Записная книжка (данные в XML-файле book.xml).        */

/*           Вставка новых элементов в XML-файл                    */

/*******************************************************************/

//Объявляем переменные

var

 WshShell,

 BasePath,  //Путь к текущему каталогу

 PathBook,  //Путь к файлу с данными

 XMLDoc,    //XML-файл с данными

 NomRec=0,  //Счетчик количества записей

 PersonRec, //Объект для хранения данных об одном человеке

 PersonArr; //Массив для хранения объектов PersonRec

//Инициализируем константы для диалоговых окон

var vbYesNo=4,vbQuestion=32,vbInformation=64,vbYes=6,vbOkOnly=0;

//Конструктор объекта Person

function Person(LastName,Name,Phone,Street,House,App,Note) {

 this.LastName=LastName; //Фамилия

 this.Name=Name;         //Имя

 this.Phone=Phone;       //Телефон

 this.Street=Street;     //Улица

 this.House=House;       //Дом

 this.App=App;           //Квартира

 this.Note=Note;         //Примечание

}

//Заполнение полей объекта PersonRec

function MakePersonRec() {

 //Создаем экземпляр PersonRec объекта Person

 PersonRec=new Person();

 //Заполняем поля объекта PersonRec

 PersonRec.LastName="Сидоров";

 PersonRec.Name="Антон";

 PersonRec.Phone="18-18-18";

 PersonRec.Street="Саранская";

 PersonRec.House="12";

 PersonRec.App="4";

 PersonRec.Note="Запись добавлена из сценария";

}

//Сохранение данных из объекта PersonRec в XML-файле

function RecordToFile(PersRec) {

 //Объявляем переменные

 var Root,NewElem,s;

 //Создаем объект DOMDocument

 XMLDoc = WScript.CreateObject("Msxml.DOMDocument");

 //Загружаем XML-файл

 XMLDoc.load(PathBook);

 //Сохраняем в переменной Root ссылку на корневой элемент

 //документа

 Root=XMLDoc.documentElement;

 //Создаем XML-элемент Person

 NewElem=XMLDoc.createElement("Person");

 //Добавляем новый элемент в XML-файл

 Root.appendChild(NewElem);

 //Сохраняем в переменной Root ссылку на последний добавленный

 //элемент Person

 Root=Root.lastChild;

 //Создаем элемент LastName

 NewElem=XMLDoc.createElement("LastName");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента LastName

 //значение поля LastName объекта PersRec

 Root.lastChild.text=PersRec.LastName;

 //Создаем элемент Name

 NewElem=XMLDoc.createElement("Name");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента Name

 //значение поля Name объекта PersRec

 Root.lastChild.text=PersRec.Name;

 //Создаем элемент Phone

 NewElem=XMLDoc.createElement("Phone");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента Phone

 //значение поля Phone объекта PersRec

 Root.lastChild.text=PersRec.Phone;

 //Создаем элемент Street

 NewElem=XMLDoc.createElement("Street");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента Street

 //значение поля Street объекта PersRec

 Root.lastChild.text=PersRec.Street;

 //Создаем элемент House

 NewElem=XMLDoc.createElement("House");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента House

 //значение поля House объекта PersRec

 Root.lastChild.text=PersRec.House;

 //Создаем элемент App

 NewElem=XMLDoc.createElement("App");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента App

 //значение поля House объекта PersRec

 Root.lastChild.text=PersRec.App;

 //Создаем элемент Note

 NewElem=XMLDoc.createElement("Note");

 //Добавляем новый элемент в XML-файл (внутри элемента Person)

 Root.appendChild(NewElem);

 //Подставляем в качестве содержимого элемента App

 //значение поля House объекта PersRec

 Root.lastChild.text=PersRec.Note;

 //Сохраняем содержимое XML-файла на диске

 XMLDoc.save(PathBook);

}

//Добавление новой записи в книжку

function AddRecord() {

 //Заполняем поля объекта PersonRec

 MakePersonRec();

 //Сохраняем данные из объекта PersonRec в XML-файл

 RecordToFile(PersonRec);

}

//Построение путей к файлам

function InitPath() {

 BasePath=WshShell.CurrentDirectory+"\\";

 //Путь к файлу с данными

 PathBook=BasePath+"book.xml";

}

//Основная запускная функция

function Main() {

 var Res;

 //Создаем объект WshShell

 WshShell = WScript.CreateObject("WScript.Shell");

 //Определяем пути к файлам

 InitPath();

 //Запрос на создание нового ключа

 Res=WshShell.Popup("Добавить запись в \n"+PathBook+"?", 0,

  "Работа с XML-файлом", vbQuestion+vbYesNo);

 if (Res==vbYes) { //Нажата кнопка Да

  //Добавляем новую запись в книжку

  AddRecord();

  //Выводим информацию на экран

  WshShell.Popup("Новая запись\n\n"+PersonRec.LastName+" "+

   PersonRec.Name+"\n"+PersonRec.Phone+"\n"+

   PersonRec.Street+", "+PersonRec.House+"-"+PersonRec.App+"\n\n"+

   "добавлена в файл "+PathBook, 0,

   "Работа с XML-файлом", vbInformation+vbOkOnly);

 }

}

/*******************  Начало  **********************************/

Main();

/*************  Конец *********************************************/ 

 

Поиск и удаление записи из книжки 

Рассмотрим сценарий FindAndDelRecord.wsf, с помощью которого можно будет полностью удалить из записной книжки данные о человеке, фамилия которого введена в диалоговом окне (рис. 6.1).

Рис. 6.1. Ввод фамилии для удаления

Сценарий FindAndDelRecord.wsf реализован в виде WS-файла для того, чтобы можно было внутри JScript-кода воспользоваться функцией InputName на языке VBScript, которая реализует диалоговое окно с полем ввода, показанное на рис. 6.1:

Function InputName

 'Вводим фамилию в диалоговом окне

 InputName = InputBox("Введите фамилию для удаления:", "Записная книжка")

End Function

Фамилия, которую следует найти и удалить в записной книжке, сохраняется в глобальной переменной LastName:

LastName=InputName();

Непосредственно поиск и удаление данных производятся в функции FindAndDelRecord(). Здесь, как и во всех рассмотренных ранее примерах, сначала создается экземпляр XMLDoc объекта DOMDocument, с помощью метода load загружается файл book.xml и указатель на корневой элемент сохраняется в переменной Root:

XMLDoc = WScript.CreateObject("Msxml.DOMDocument");

XMLDoc.load(PathBook);

Root=XMLDoc.documentElement;

Для выделения в записной книжке всех фамилий, которые требуется удалить, используется метод selectNodes(). В качестве аргумента этого метода подставляется строка sSelect, которая указывает, что нужно искать расположенные внутри элементов Person элементы с именем LastName и значением, которое совпадает со значением переменной LastName. Все найденные элементы помещаются в коллекцию NodeList:

//Формируем строку для поиска фамилии

sSelect="Person/LastName[text()='"+LastName+"']";

//Создаем коллекцию NodeList всех элементов LastName,

//значение которых совпадает со значением переменной LastName

NodeList=XMLDoc.documentElement.selectNodes(sSelect);

Если найден хотя бы один подходящий элемент LastName, т.е. коллекция NodeList не является пустой, то для каждого такого элемента в цикле for определяется родительский элемент (в нашем случае это элемент Person) и этот элемент вместе со всеми своими дочерними элементами удаляется с помощью метода removeChild():

for (i=0;i<=NodeList.length-1;i++) {

 //Определяем родительский элемент (Person) для найденного

 //элемента LastName

 Parent=NodeList.item(i).parentNode;

 //Удаляем элемент Person вместе со всеми его дочерними элементами

 Root.removeChild(Parent);

 //Выводим диалоговое окно с сообщением

 WshShell.Popup("Запись удалена!",0,

  "Работа с XML-файлом",vbInformation+vbOkOnly);

}

После удаления всех записей содержимое XML-файла book.xml сохраняется на диске с помощью метода save():

XMLDoc.save(PathBook);

Полный текст сценария FindAndDelRecord.wsf приводится в листинге 6.6.

Листинг 6.6. Поиск и удаление данных в XML-файле с помощью XML DOM

Имя: FindAndDelRecord.wsf

Описание: Записная книжка (данные в XML-файле book.xml).

          Поиск и удаление элементов из XML-файла