Чтение XML
Перебор элементов XML-документа
Для чтения XML-документа предназначен экземпляр типа ЧтениеXml
. В общем случае читать XML-документ можно из экземпляра типа, производного от ПотокЧтения
. Мы будем рассматривать чтение документа из файла. В качестве примера файла рассмотрим фрагмент манифеста универсального приложения ОС Windows. Это достаточно сложный XML-документ, который позволит увидеть основные особенности чтения таких документов.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Package IgnorableNamespaces="uap mp build"
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build">
<mp:PhoneIdentity
PhoneProductId="A588A326-FD4F-441C-83B2-AA0B8554C548"
PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>ms-resource:AppName</DisplayName>
<PublisherDisplayName>1C LLC</PublisherDisplayName>
<Logo>icon_50x50.png</Logo>
</Properties>
<Resources>
<Resource Language="EN-US"/>
</Resources>
<Capabilities>
<uap:Capability Name="appointments"/>
<uap:Capability Name="contacts"/>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<Capability Name="internetClientServer"/>
<uap:Capability Name="musicLibrary"/>
<uap:Capability Name="picturesLibrary"/>
<uap:Capability Name="removableStorage"/>
<uap:Capability Name="videosLibrary"/>
<DeviceCapability Name="location"/>
<DeviceCapability Name="webcam"/>
<DeviceCapability Name="microphone"/>
<DeviceCapability Name="proximity"/>
</Capabilities>
<build:Metadata>
<build:Item Name="cl.exe" Version="19.16.27030.1 built by: vcwrkspc"/>
<build:Item Name="VisualStudio" Version="15.0"/>
<build:Item Name="OperatingSystem" Version="6.3.9600.16384 (winblue_rtm.130821-1623)"/>
<build:Item Name="Microsoft.Build.AppxPackage.dll" Version="15.0.28307.104"/>
<build:Item Name="ProjectGUID" Value="{15630E4C-5D90-44AB-9CF0-FBC27700DDAA}"/>
<build:Item Name="OptimizingToolset" Value="None"/>
<build:Item Name="TargetRuntime" Value="Native"/>
<build:Item Name="Microsoft.Windows.UI.Xaml.Build.Tasks.dll" Version="15.0.28307.102"/>
<build:Item Name="WindowsMobile" Version="10.0.17763.0"/>
<build:Item Name="MakePri.exe" Version="10.0.17763.132 (WinBuild.160101.0800)"/>
</build:Metadata>
</Package>
Рассматриваемый экземпляр читает XML-документ строго последовательно. Каждый элемент имеет свое имя, которое отображается в свойство Имя
экземпляра ЧтениеXml
. Простейший пример такого чтения будет выглядеть примерно следующим образом:
метод метод ЧтениеXml(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пока Чтение.Следующий()
// Читаем имя текущего узла
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя)
;
возврат СодержимоеXML
;
Вызов метода Следующий()
приводит к последовательному обходу всех элементов читаемого XML-документа. Когда данный метод вернет значение Ложь
, это будет означать, что файл завершился. Результат исполнения этого программного кода, записанный в массив строк СодержимоеXML
, будет не очень понятным (приведен фрагмент):
Имя узла - Package
Имя узла - mp:PhoneIdentity
Имя узла - mp:PhoneIdentity
Имя узла - Properties
Имя узла - DisplayName
Имя узла -
Имя узла - DisplayName
Имя узла - PublisherDisplayName
Имя узла -
Имя узла - PublisherDisplayName
Имя узла - Logo
Имя узла -
Имя узла - Logo
Имя узла - Properties
...
Первое, что смущает при взгляде на результат работы программы, — некоторые элементы выводятся один раз, некоторые — два раза, а некоторые элементы вообще не имеют имени. Попробуем разобраться с этим вопросом.
Каждый элемент XML имеет открывающий и закрывающий тег. При этом оба этих тега в теле документа имеют одинаковое имя: <tag>
текст</tag>
. Закрывающий тег несколько отличается, но это нам сейчас не интересно. Экземпляр ЧтениеXml
читает наш документ последовательно. При чтении отдельно читается начало элемента и отдельно — его окончание. А так как имена в открывающем и закрывающем тегах одинаковые, мы видим две строки с одним именем. Соответственно, если строка с именем только одна, то скорее всего, до закрывающего тега еще не дошли.
Чтобы определить, какой элемент в данный момент считан из нашего документа, тип ЧтениеXml
предоставляет свойство ВидУзла
. С помощью этого свойства мы можем проверить наше предыдущее утверждение. Перепишем строку СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя)
из примера:
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя + ", тип - " + Чтение.ВидУзла)
В результате работы нашего примера в массиве СодержимоеXML
будут следующие элементы (приведен фрагмент того же размера):
Имя узла - Package, тип - StartElement
Имя узла - mp:PhoneIdentity, тип - StartElement
Имя узла - mp:PhoneIdentity, тип - EndElement
Имя узла - Properties, тип - StartElement
Имя узла - DisplayName, тип - StartElement
Имя узла - , тип - Text
Имя узла - DisplayName, тип - EndElement
Имя узла - PublisherDisplayName, тип - StartElement
Имя узла - , тип - Text
Имя узла - PublisherDisplayName, тип - EndElement
Имя узла - Logo, тип - StartElement
Имя узла - , тип - Text
Имя узла - Logo, тип - EndElement
Имя узла - Properties, тип - EndElement
...
Мы видим, что тип элемента (или узла XML-документа) в каждой строке вывода изменяется. В текущем примере мы видим три разных значения:
StartElement
— таким образом описывается начало элемента.EndElement
— таким образом описывается окончание элемента.Text
— таким типом отмечается содержимое узла XML-документа, если это содержимое не является другим элементом.
Наши утверждения, высказанные ранее, подтвердились практически. Также получили объяснения элементы, которые не имеют имени. В XML-документе узлы, которые имеют содержимое, выглядят следующим образом:
`<tag>`содержимое`</tag>`
В то же время не все узлы такое содержимое имеют. Для того чтобы определить, имеет узел содержимое или нет, предназначено свойство ЧтениеXml.ИмеетЗначение
.
Наш пример, модифицированный для того, чтобы выводить содержимое для элементов, которые его содержат, выглядит следующим образом:
метод ЧтениеXml(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пока Чтение.Следующий()
// Читаем имя текущего узла
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя + ", тип - " + Чтение.ВидУзла)
если Чтение.ИмеетЗначение
СодержимоеXML.Добавить("Содержимое: " + Чтение.Значение)
;
;
возврат СодержимоеXML
;
Массив СодержимоеXML
будет содержать следующие элементы:
Имя узла - Package, тип - StartElement
Имя узла - mp:PhoneIdentity, тип - StartElement
Имя узла - mp:PhoneIdentity, тип - EndElement
Имя узла - Properties, тип - StartElement
Имя узла - DisplayName, тип - StartElement
Имя узла - , тип - Text
Содержимое: ms-resource:AppName
Имя узла - DisplayName, тип - EndElement
Имя узла - PublisherDisplayName, тип - StartElement
Имя узла - , тип - Text
Содержимое: 1C LLC
Имя узла - PublisherDisplayName, тип - EndElement
Имя узла - Logo, тип - StartElement
Имя узла - , тип - Text
Содержимое: icon_50x50.png
Имя узла - Logo, тип - EndElement
Имя узла - Properties, тип - EndElement
...
Кроме безусловного чтения следующего элемента, с помощью экземпляра ЧтениеXml
можно читать элементы какого-то заранее известного имени. Чтение будет выполняться без учета иерархии элементов. Для того, чтобы выполнить такое чтение, необходимо использовать метод СледующийДо()
. Параметром метода является имя элемента, начало которого необходимо прочитать. После того как выполнено позиционирование на требуемый элемент, необходимо вызвать метод Следующий()
, а затем снова вызвать метод СледующийДо()
. Пример демонстрирует чтение элементов с именем Capability
. Всего их три.
метод ЧтениеXmlОпределенногоЭлемента(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пока Чтение.СледующийДо("Capability")
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя + ", тип - " + Чтение.ВидУзла)
если Чтение.ИмеетЗначение
СодержимоеXML.Добавить("Содержимое: " + Чтение.Значение)
;
Чтение.Следующий()
;
возврат СодержимоеXML
;
Если какой-либо узел нам не нужен, мы можем пропустить все содержимое этого узла и возобновить чтение с узла, который следует в нашем XML-документе после пропускаемого узла. Узел пропускается полностью, включая все вложенные узлы, если таковые имеются. Для того чтобы пропустить узел, необходимо использовать метод Пропустить()
. В следующем примере мы дойдем до узла <Capabilities>
, пропустим его и сразу окажемся на стартовом элементе узла <build:Metadata>
.
метод ЧтениеXmlСПропускомЭлемента(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пер ЕщеЕстьЭлементы = Чтение.Следующий()
пока ЕщеЕстьЭлементы
если Чтение.ВидУзла == ВидУзлаXml.НачалоЭлемента
если Чтение.Имя == "Capabilities"
// Пропускаем этот узел!
ЕщеЕстьЭлементы = Чтение.Пропустить()
продолжить
иначе
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя + ", тип - " + Чтение.ВидУзла)
;
;
ЕщеЕстьЭлементы = Чтение.Следующий()
;
возврат СодержимоеXML
;
Также при переборе элементов полезным может оказаться метод ЭтоПустойЭлемент()
, который позволяет понять, что у текущего узла нет значения. Другими словами, метод ЭтоПустойЭлемент()
вернет значение Истина
для узла вида <tag/>
.
Кроме того, для поиска элементов можно использовать метод СледующийПоВыражениюXPath, который в качестве аргумента принимает выражение языка запросов XPath. Например, так может выглядеть выражение XPath: /Package/Capabilities/Capability[@Name = '%{CapabilityName}']
, где CapabilityName
— это имя переменной. Данный метод использует упрощенный вариант языка запросов (подробнее см. здесь).
Чтение атрибутов узла XML-документа как данных различных типов
Узлы XML-документа могут иметь один или несколько атрибутов. Зачастую смысловая информация узла расположена именно в атрибутах, а не в содержимом элемента. Для того чтобы работать с атрибутами узла XML, встроенный язык предоставляет несколько методов, среди которых:
КоличествоАтрибутов()
— позволяет получить количество атрибутов у данного элемента.ИмяАтрибута()
— позволяет получить имя атрибута по индексу.ЗначениеАтрибута()
— позволяет получить значение атрибута по имени атрибута.ЗначениеАтрибутаПоИндексу()
— позволяет получить значение атрибута по индексу атрибута.
Работать с атрибутами можно только для такого узла, который является началом элемента. Расширим пример чтения XML-документа кодом, который будет отображать атрибуты каждого узла (если атрибуты присутствуют). Код будет иметь следующий вид:
метод ЧтениеАтрибутовXml(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пока Чтение.Следующий()
СодержимоеXML.Добавить("Имя узла - " + Чтение.Имя + ", тип - " + Чтение.ВидУзла)
если Чтение.ИмеетЗначение
СодержимоеXML.Добавить("Содержимое: " + Чтение.Значение)
;
если Чтение.ВидУзла != ВидУзлаXml.НачалоЭлемента
продолжить
;
для индекс = 0 по Чтение.КоличествоАтрибутов() - 1
пер ИмяАтрибута = Чтение.ИмяАтрибута(индекс)
СодержимоеXML.Добавить("\тАтрибут: " + ИмяАтрибута +
" = " + Чтение.ЗначениеАтрибута(ИмяАтрибута))
;
;
возврат СодержимоеXML
;
Результат работы этого примера будет следующим:
Имя узла - Package, тип - StartElement
Атрибут: IgnorableNamespaces = uap mp build
Имя узла - mp:PhoneIdentity, тип - StartElement
Атрибут: PhoneProductId = A588A326-FD4F-441C-83B2-AA0B8554C548
Атрибут: PhonePublisherId = 00000000-0000-0000-0000-000000000000
Имя узла - mp:PhoneIdentity, тип - EndElement
Имя узла - Properties, тип - StartElement
Имя узла - DisplayName, тип - StartElement
Имя узла - , тип - Text
Содержимое: ms-resource:AppName
Имя узла - DisplayName, тип - EndElement
Имя узла - PublisherDisplayName, тип - StartElement
Имя узла - , тип - Text
Содержимое: 1C LLC
Имя узла - PublisherDisplayName, тип - EndElement
Имя узла - Logo, тип - StartElement
Имя узла - , тип - Text
Содержимое: icon_50x50.png
Имя узла - Logo, тип - EndElement
Имя узла - Properties, тип - EndElement
...
Метод ЗначениеАтрибута()
возвращает значение типа Строка
. Однако может возникнуть потребность в чтении атрибутов как данных других типов. Существует методы для чтения атрибутов элементов XML-документа, которые возвращают значения следующих типов:
Ууид
/Число
/Булево
Байты
/БайтыBase64
Время
/ДатаВремя
/Дата
/Длительность
/Момент
Все эти методы начинаются с префикса ЗначениеАтрибутаКак
. Например, для того чтобы прочитать атрибут элемента как Число
, следует использовать метод:
ЗначениеАтрибутаКакЧисло(Имя: Строка, ПространствоИмен: Строка? = Неопределено): Число
Чтение содержимого узла XML-документа как данных различных типов
Для чтения содержимого элемента предназначены свойства ИмеетЗначение
и Значение
типа ЧтениеXml
. С помощью первого свойства можно узнать, имеет ли элемент содержимое, а второе свойство поз воляет его считать. Однако значение возвращается в текстовом виде, что не всегда бывает удобно. Если тип содержимого элементов XML-документа известен заранее, для чтения значений можно использовать методы типа ЧтениеXml
, начинающиеся с префикса ПрочитатьСодержимоеКак
:
-
ПрочитатьСодержимоеКакБайты()
Читает содержимое узла как шестнадцатеричное число и преобразует его к значению типа
Байты
. -
ПрочитатьСодержимоеКакБайтыBase64()
Читает содержимое узла как число в записи Base64 и преобразует его к значению типа
Байты
. -
ПрочитатьСодержимоеКакБулево()
Читает значение узла и преобразует его к типу
Булево
:- текст true и 1 преобразуются в значение
Истина
; - текст false и 0 преобразуются в значение
Ложь
.
- текст true и 1 преобразуются в значение
-
ПрочитатьСодержимоеКакВремя()
Читает содержимое узла и преобразует его к значению типа
Время
. -
ПрочитатьСодержимоеКакДатаВремя()
Читает содержимое узла и преобразует его к значению типа
ДатаВремя
. -
ПрочитатьСодерж имоеКакДату()
Читает содержимое узла и преобразует его к значению типа
Дата
. -
ПрочитатьСодержимоеКакДлительность()
Читает содержимое узла и преобразует его к значению типа
Длительность
. -
ПрочитатьСодержимоеКакМомент(ЧасовойПояс = ЧасовойПояс.Текущий())
Читает содержимое узла и преобразует его к значению типа
Момент
. Если у содержимого узла не указан часовой пояс, для преобразования будет использован часовой пояс, указанный в параметре ЧасовойПояс. -
ПрочитатьСодержимоеКакСтроку
Читает содержимое узла и преобразует его к значению типа
Строка
. -
ПрочитатьСодержимоеКакУуид()
Читает содержимое узла и преобразует его к значению типа
Ууид
. -
ПрочитатьСодержимоеКакЧисло()
Читает содержимое узла и преобразует его к типу
Число
.
При использовании вышеперечисленных методов перед преобразованием от значения автоматически отрезаются пробелы в начале и конце.
Пространства имен
Имена элементов и атрибутов в XML-документ могут быть квалифицированными и неквалифицированными (локальными). Квалифицированное имя уникально в рамках XML-документа. Квалифицированное имя состоит из префикса, определяющего пространство имен, и локального имени. Префикс и локальное имя разделяются символом двоеточия (":"). Когда XML-документ читается с помощью типа ЧтениеXml
, то программист может получить доступ к любой части имени элемента или атрибута:
- Для элемента:
- Свойство
Имя
. Содержит квалифицированное имя текущего узла. Квалифицированное имя состоит из префикса и локального имени (разделенного символом двоеточия). - Свойство
Префикс
. Содержит префикс пространства имен для текущего узла. - Свойство
ЛокальноеИмя
. Содержит локальное имя текущего узла документа. - Свойство
ПространствоИмен
. Данное свойство позволяет получить URI пространства имен. Префикс этого пространства имен можно получить с помощью свойстваПрефикс
.
- Свойство
- Для атрибута:
- Метод
ИмяАтрибута(Индекс: Число)
. Возвращает квалифицированное имя атрибута по индексу Индекс. Квалифицированное имя состоит из префикса и локального имени (разделенного символом двоеточия). - Метод
ПрефиксАтрибута(Индекс: Число)
. Возвращает префикс пространства имен для атрибута с указанным индексом. - Метод
ЛокальноеИмяАтрибута(Индекс: Число)
. Возвращает локальное имя атрибута по индексу Индекс. - Метод
ПространствоИменАтрибута(Индекс: Число)
. Данный метод позволяет получить URI пространства имен атрибута по индексу Индекс. Префикс пространства имен атрибута можно получить с помощью методаПрефиксАтрибута(Индекс: Число)
.
- Метод
Далее приведен пример программного кода, который отображает всю информацию об узлах и атрибутах XML-документа, связанную с пространствами имен. Будут выведены квалифицированное имя, префикс имени, локальное имя и URI пространства имен.
метод ЧтениеXmlСПространствомИмен(): Массив<Строка>
пер ВременныйКаталог = СредаИсполнения.ПолучитьПеременную("temp")
пер Файл = новый Файл(ВременныйКаталог + "\\manifest.xml")
пер СодержимоеXML: Массив<Строка>
пер Чтение = новый ЧтениеXml(Файл.ОткрытьПотокЧтения())
пока Чтение.Следующий()
если Чтение.ВидУзла == ВидУзлаXml.НачалоЭлемента
СодержимоеXML.Добавить("Имя узла: " + Чтение.Имя)
СодержимоеXML.Добавить("\тПрефикс: " + Чтение.Префикс)
СодержимоеXML.Добавить("\тЛокальное имя: " + Чтение.ЛокальноеИмя)
СодержимоеXML.Добавить("\тURI пространства имен: " + Чтение.ПространствоИмен)
для индекс = 0 по Чтение.КоличествоАтрибутов() - 1
СодержимоеXML.Добавить("\т\тИмя атрибута: " + Чтение.ИмяАтрибута(индекс))
СодержимоеXML.Добавить("\т\ т\тПрефикс: " + Чтение.ПрефиксАтрибута(индекс))
СодержимоеXML.Добавить("\т\т\тЛокальное имя: " + Чтение.ЛокальноеИмяАтрибута(индекс))
СодержимоеXML.Добавить("\т\т\тURI пространства имен: " + Чтение.ПространствоИменАтрибута(индекс))
;
;
;
возврат СодержимоеXML
;