81 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Пример работы с XPath в Java. Поиск в XML и выборка данных

XPath примеры – шпаргалка для разбора страниц

Примеры использования xpath из практики парсинга информации с сайтов. Приведены участки кода xpath.

Получить текст заголовока h1

Получить текст заголовока с классом produnctName

Получить значение определенного span по классу

Получить значение атрибута title у кнопки с классом addtocart_button

Текст ссылки

Получить url значение атрибута href ссылки

Изображение src

Изображение сразу за определенным элементом в DOM, ось following

Изображение в 4 div по счету

XPath (XML Path Language) — язык запросов к элементам XML-документа. Разработан для организации доступа к частям документа XML в файлах трансформации XSLT и является стандартом консорциума W3C. XPath призван реализовать навигацию по DOM в XML.

XML имеет древовидную структуру. У элемента дерева всегда существуют потомки и предки, кроме корневого элемента, у которого предков нет, а также тупиковых элементов (листьев дерева), у которых нет потомков.

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

Функции над множествами узлов

  • * — обозначает любое имя или набор символов по указанной оси, например: * — любой дочерний узел; @* — любой атрибут.
  • $name — обращение к переменной, где name — имя переменной или параметра.
  • [] — дополнительные условия выборки или, что то же самое, предикат шага адресации. Должен содержать логическое значение. Если содержит числовое, считается что это порядковый номер узла, что эквивалентно приписыванию перед этим числом выражения «position()=»
  • <> — если применяется внутри тега другого языка (например HTML), то XSLT процессор рассматривает содержимое фигурных скобок как XPath.
  • / — определяет уровень дерева, то есть разделяет шаги адресации
  • | — объединяет результат. То есть, можно написать несколько путей разбора через знак | и в результат такого выражения войдёт всё, что будет найдено любым из этих путей.
  • node-set node()

Возвращает все узлы. Вместо этой функции часто используют заменитель ‘*’, но, в отличие от звездочки, функция node() возвращает и текстовые узлы.

Возвращает набор текстовых узлов;

  • node-set current()

Возвращает множество из одного элемента, который является текущим. Если мы делаем обработку множества с условиями, то единственным способом дотянуться из этого условия до текущего элемента будет данная функция.

  • number position()

Возвращает позицию элемента в множестве. Корректно работает только в цикле

Возвращает номер последнего элемента в множестве. Корректно работает только в цикле

  • number count(node-set)

Возвращает количество элементов в node-set.

  • string name(node-set?)

Возвращает полное имя первого тега в множестве.

  • string namespace-uri(node-set?)

Возвращает ссылку на url определяющий пространство имён.

  • string local-name(node-set?)

Возвращает имя первого тега в множестве, без пространства имён.

  • node-set id(object)

Находит элемент с уникальным идентификатором

Оси — это база языка XPath. Для некоторых осей существуют сокращённые обозначения.

  • ancestor:: — Возвращает множество предков.
  • ancestor-or-self:: — Возвращает множество предков и текущий элемент.
  • attribute:: — Возвращает множество атрибутов текущего элемента. Это обращение можно заменить на «@»
  • child:: — Возвращает множество потомков на один уровень ниже. Это название сокращается полностью, то есть его можно вовсе опускать.
  • descendant:: — Возвращает полное множество потомков (то есть, как ближайших потомков, так и всех их потомков).
  • descendant-or-self:: — Возвращает полное множество потомков и текущий элемент. Выражение «/descendant-or-self::node()/» можно сокращать до «//». С помощью этой оси, например, можно вторым шагом организовать отбор элементов с любого узла, а не только с корневого: достаточно первым шагом взять всех потомков корневого. Например, путь «//span» отберёт все узлы span документа, независимо от их положения в иерархии, взглянув как на имя корневого, так и на имена всех его дочерних элементов, на всю глубину их вложенности.
  • following:: — Возвращает необработанное множество, ниже текущего элемента.
  • following-sibling:: — Возвращает множество элементов на том же уровне, следующих за текущим.
  • namespace:: — Возвращает множество, имеющее пространство имён (то есть присутствует атрибут >

    Если необходимо послать кого-то купить литр молока, что проще сказать этому человеку? “Пожалуйста, сходи купи литр молока” или “Выйди из дома через переднюю дверь. Поверни налево. Пройди три квартала. Поверни направо. Пройди половину квартала. Поверни направо и войди в магазин. Подойди к четвертому стеллажу. Пройди пять метров вдоль стеллажа. Поверни налево. Возьми литровый пакет молока. Принеси его к кассе. Заплати за молоко. Затем возвращайся домой”. Это нелепо! Большая часть взрослых людей достаточно умна, чтобы самостоятельно купить молоко, довольствуясь лишь инструкцией типа “Пожалуйста, сходи купи литр молока”.

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

    XPath

    Среди всех языков запросов Structured Query Language (SQL) — это язык, разработанный и оптимизированный для поиска в определенных видах реляционных баз данных. Список других, менее известных языков запросов включает в себя Object Query Language (OQL) и XQuery. Однако предметом рассмотрения этой статьи является XPath, язык запросов, разработанный для поиска информации в XML-документах. Например, простой запрос на языке Xpath для поиска документе названия всех книг, автором которых является Нил Стивенсон (Neal Stephenson), выглядит примерно так:

    Для сравнения, код для выполнения аналогичного действия с использованием «чистой» DOM модели выглядит как в листинге 1:

    Листинг 1. Код, использующий DOM, для поиска названий книг, написанных Нилом Стивенсоном

    Хотите верьте – хотите нет, но DOM-код в листинге 1 все-таки не так хорош и изящен, как простое выражение на языке XPath. Какой код проще и удобнее написать, отладить и сопровождать? По-моему, ответ очевиден!

    Однако как бы он не был выразителен, XPath – это все-таки не язык Java, фактически, XPath даже не является языком программирования. Существует очень много вещей, которые невозможно выполнить с помощью XPath, включая даже запросы, которые нельзя сформировать. Например, XPath не может найти все книги, для которых указан некорректный International Standard Book Number (ISBN) или найти всех авторов, для которых сторонняя база данных показывает, что авторские гонорары начисляются в текущий момент. К счастью, можно интегрировать XPath в программы, написанные на Java, а значит, получить все лучшее из двух миров: Java — для всех тех вещей, с которыми хорошо справляется Java, и XPath для всего того, с чем хорошо справляется Xpath.

    До сих пор набор интерфейсов программирования приложений (API), с помощью которого Java-программа выполняла XPath-запросы, зависел от типа реализации XPath. Xalan имел один набор API, Saxon — другой, а остальные реализации имели полностью собственные наборы API. Это значило, что код оказывался привязан к одному продукту. В общем случае хотелось бы без особых трудностей и переписывания кода провести эксперименты с различными реализациями по определению характеристик эффективности.

    По этой причине в Java 5 включен пакет javax.xml.xpath — он предоставляет реализацию и объектно-независимую модель библиотеки XPath. Этот пакет также доступен в Java версии 1.3 и выше, если дополнительно установить Java API for XML Processing (JAXP) 1.3. Из числа сторонних продуктов Xalan 2.7 и Saxon 8 также включают в себя реализацию этой библиотеки.

    Простой пример

    Сейчас будет продемонстрировано как это работает на практике. Также будут подробнее рассмотрены некоторые детали. Предполагается, что для запросов есть список книг, в котором могут быть найдены книги, написанные Нилом Стивенсоном. Полагается также, что список книг имеет такой же вид, как в листинге 2:

    Листинг 2. XML-документ, содержащий информацию о книгах
    Абстрактные фабрики

    The XPathFactory — это абстрактная фабрика. Шаблон проектирования «абстрактная фабрика» позволяет выбрать API для поддержки конкретной объектной модели, такой как DOM, JDOM и XOM. Чтобы выбрать новую модель, необходимо передать Uniform Resource Identifier (URI), идентифицирующий объектную модель, методу XPathFactory.newInstance() . Например, http://xom.nu/ выбирает объектную модель XOM. Однако на практике, DOM — это единственная объектная модель, поддерживаемая API на данный момент.

    Запрос XPath, который выбирает все необходимые книги из документа, достаточно прост: //book[author=”Neal Stephenson”] . Чтобы найти только названия этих книг, требуется всего лишь небольшое изменение запроса — выражение будет выглядеть следующим образом: //book[author=”Neal Stephenson”]/title . Наконец, найдем то, что действительно необходимо — это текст узла-потомка элемента title . Для этого требуется еще одно небольшое изменение, полное выражение будет следующим: //book[author=”Neal Stephenson”]/title/text() .

    Теперь рассмотрим программу, которая использует этот поисковый запрос в программе на языке Java и выводит затем названия всех найденных книг. Прежде всего необходимо загрузить документ в объект Document . Для простоты, будем полагать, что список книг содержится в файле books.xml в текущем каталоге. Ниже дан простой фрагмент кода, который обрабатывает документ и создает соответствующий объект Document :

    Листинг 3. Обработка документа с помощью JAXP

    Итак, это всего лишь стандартные JAXP и DOM, ничего нового.

    Теперь создаем XPathFactory :

    Затем используется эта фабрика для создания объекта XPath :

    XPath компилирует XPath-выражение:

    Немедленное исполнение: Если необходимо использовать выражение XPath только один раз, то можно пропустить шаг компиляции и вместо этого вызвать непосредственно метод evaluate() в объекте XPath . Однако если необходимо использовать одно и то же выражение несколько раз, то компиляция сделает обработку запроса значительно быстрее.

    Наконец, необходимо выполнить запрос XPath для получения результата. Выражение исполняется по отношению к определенному по контексту узлу, которым в данном случае является весь документ. Также необходимо явно задать тип возвращаемого результата. В примере тип NODE задается как тип результата исполнения выражения:

    Теперь можно сохранить результат в DOM NodeList , затем итеративно обратиться к каждому элементу, чтобы найти все названия:

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

    Листинг 4. Программа для поиска в XML-документе с помощью фиксированного XPath выражения

    Модель данных XPath

    При совместной разработке на двух различных языках программирования, таких XPath и Java, нужно ожидать некоторых заметных “швов” там, где соединяются два языка программирования. Не все совместится достаточно хорошо. XPath и Java имеют различную систему типов данных. В частности XPath 1.0 имеет только четыре основных типа данных:

    Java, безусловно, имеет значительно большее количество возможных типов данных, включая объектные типы данных, определяемые пользователем.

    Многие выражения XPath, особенно запрашивающие отдельные элементы XML-документа, возвращают результат типа node-set. Однако есть также другие возможности. Например выражение на языке XPath count(//book) возвращает количество книг в документе. Результат работы другого выражения на языке XPath count(//book[@author=”Neal Stephenson”]) > 10 имеет тип результата boolean: возвращаемое значение равно true, если больше десяти книг Нила Стивенсона содержится в документе, и false, если десять и менее.

    Метод evaluate() возвращает выражение типа Object . . Что именно будет результатом зависит от выполнения XPath-выражения, также как и тип запрашиваемых данных. В общем случае, XPath

    • number cоответствует в java.lang.Double
    • string cоответствует в java.lang.String
    • boolean cоответствует в java.lang.Boolean
    • node-set cоответствует в org.w3c.dom.NodeList
    XPath 2

    До сих пор полагалось, что используется XPath 1.0. XPath 2 значительно расширяет и пересматривает систему типов. Основное введенное изменение в Java XPath API для поддержки XPath 2 — это дополнительные константы для новых типов возвращаемых значений, введенных в XPath 2.

    Когда выполняется XPath выражение в Java, второй аргумент определяет тип возвращаемого параметра. Существует пять возможных типов возвращаемых параметров, все они имеют определены как константы в классе javax.xml.xpath.XPathConstants со следующими именами:

    • XPathConstants.NODESET
    • XPathConstants.BOOLEAN
    • XPathConstants.NUMBER
    • XPathConstants.STRING
    • XPathConstants.NODE

    Необходимо заметить, что значение XPathConstants.NODE не является в действительности типом данных XPath. Это значение используется только тогда, когда нет уверенности, что выражение на XPath вернет значение, состоящее из единственного узла или когда не требуется более одного значения. Если выражение на XPath возвращает более одного узла и был определен тип возвращаемого параметра как XPathConstants.NODE , то evaluate() вернет первый найденный в документе узел, удовлетворяющий заданному выражению. Если выражение на языке XPath должно возвратить пустой список и был определен тип возвращаемого параметра XPathConstants.NODE , тогда метод evaluate() вернет null.

    Если запрашиваемое преобразование типа не может быть сделано, то метод evaluate() сбрасывает исключительную ситуацию типа XPathException .

    Контекст пространства имен

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

    Однако Java-программы — это не XML-документы, поэтому обычное разрешение пространства имен не применяется. Вместо этого необходимо использовать объект, который отображает префиксы в пространство имен URI. Этот объект — экземпляр интерфейса javax.xml.namespace.NamespaceContext . Например, предположим, что документ содержит информацию о книгах в пространстве имен http://www.example.com/books, как в листинге 5:

    Листинг 5. XML-документ использует пространство имен по умолчанию

    Выражение XPath, которое находит названия всех книг Нила Стивенсона теперь становится вот таким: //pre:book[pre:author=”Neal Stephenson”]/pre:title/text() . Однако необходимо отобразить префикс pre to the URI http://www.example.com/books. в URI http://www.example.com/books. Немного странно, что интерфейс NamespaceContext не имеет реализации по умолчанию в комплекте разработчика Java (JDK) или JAXP, но это так. Тем не менее, не так уж сложно сделать такую реализацию самостоятельно. В листинге 6 показана простая реализация для одного пространства имен. Необходимо также отобразить префикс xml .

    Листинг 6. Простой контекст для связывания одного пространства имен с пространством имен, используемым по умолчанию

    Не так уж сложно использовать отображение для привязывания контекстов имен и префиксов, а также для добавления методов, которые позволяют сделать контекст пространства имен многократно используемым.

    После создания объекта NamespaceContext необходимо установить его в объект XPath перед компиляцией выражения. Теперь можно использовать в запросах те же префиксы, что и раньше. Например:

    Листинг 7. Запрос XPath, который использует пространства имен

    Преобразование функций

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

    Функции расширения, реализуемые через Java XPath API должны реализовывать интерфейс javax.xml.xpath.XPathFunction . Этот интерфейс определяет единственный метод evaluate():

    Этот метод должен возвратить значение одного из пяти типов в языке Java, которые могут быть конвертированы в типы данных XPath:

    В листинге 8 показана функция расширения, которая проверяет контрольную сумму кода ISBN и возвращает значение типа Boolean . Основное правило для подсчета контрольной суммы заключается в том, что первые девять цифр умножаются на свои позиции (то есть первая цифра умножается на единицу, вторая — на два и так далее). Полученные значения складываются и высчитывается остаток от деления на одиннадцать. Если остаток равен десяти, то последняя цифра равна X.

    Листинг 8. Функция расширения XPath для проверки кода ISBN

    Следующий шаг — это сделать функцию расширения доступной для Java-программы. Для этого необходимо установить javax.xml.xpath.XPathFunctionResolver в объект XPath перед компиляцией выражения. Преобразователь функции отображает XPath-имя и URI пространства имен для функции в Java-класс и реализует функцию. В листинге 9 приведен пример простого преобразователя функции, который отображает функцию расширения valid-isbn с пространством имен http://www.example.org/books в класс из листинга 8. Например, выражение на XPath //book[not(pre:valid-isbn(isbn))] находит все книги, чьи коды ISBN не проходят проверку на контрольную сумму.

    Листинг 9. Контекст функции-расширения valid-isbn

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

    Краткое руководство по XPath

    XPath – это невероятно гибкий, мощный, и вместе с тем сравнительно простой инструмент для навигации по документам XML. Предлагаю перевод руководства по XPath, сделанный на основе руководства консорциума W3C.

    Краткий справочник по XPath

    XPath используется для навигации по элементам и атрибутам XML-документа. XPath является одним из основных элементов в стандарте XSLT консорциума W3C.

    1 Что такое XPath

    • XPath определяет синтаксис для определения частей документа XML;
    • XPath использует выражения пути для навигации по элементам XML-документов;
    • XPath содержит библиотеку стандартных функций;
    • XPath является одним из основных элементов в XSLT;
    • XPath является рекомендацией W3C.

    Выражения XPath

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

    Стандартные функции XPath

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

    XPath используется в XSLT

    XPath является одним из основных элементов в стандарте XSLT. Без знания XPath вы не будете иметь возможность создавать XSLT-документы.

    XPath является рекомендацией консорциума W3C

    XPath стал рекомендацией W3C 16 ноября 1999 года. XPath был разработан для использования в XSLT, XPointer и другом программном обеспечении для разбора (парсинга) документов XML.

    2 Терминология XPath

    В XPath существует семь видов узлов: элемент, атрибут, текст, пространство имён, инструкции обработки, комментарии и узлы документа. XML-документы обрабатываются в виде деревьев узлов. Верхний элемент дерева называется корневым элементом. Посмотрите на следующий документ XML:

    Пример узлов в документе XML выше:

    Атомарные значения

    Атомарные значения являются узлами, не имеющие детей или родителей. Пример атомарных значений:

    Элементы

    Элементы – это атомарные значения или узлы.

    3 Отношенияузлов

    Родитель

    Каждый элемент и атрибут имеет одного родителя. В следующем примере элемент «книга» (book) является родителем элементов «название» (title), «автор» (author), «год» (year) и «цена» (price):

    Потомки

    Узлы элементов могут иметь ноль, один или более потомков. В следующем примере элементы «название», «автор», «год» и «цена» – они все потомки элемента книга:

    Элементы одного уровня

    Это узлы, которые имеют одного и того же родителя. В следующем примере элементы «название», «автор», «год» и «цена» все являются элементами одного уровня:

    Предки

    Родитель узла, родитель родителя узла и т.д. В следующем примере предки элемента «название» (title) – это элементы «книга» (book) и «книжный магазин» (bookstore):

    Потомки

    Дети узла, дети детей узла и т.д. В следующем примере потомками элемента «книжный магазин» являются элементы «книга», «название», «автор», «год» и «цена»:

    4 Синтаксис XPath

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

    Выбор узлов

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

    голоса
    Рейтинг статьи
    Читать еще:  Максимальное количество значений в enum Часть I
Ссылка на основную публикацию
Статьи c упоминанием слов: