Запрос LXML Xpath

#python #lxml

#python #lxml

Вопрос:

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

У меня есть следующий блок кода:

     def parse(self):

        parser = etree.XMLParser(remove_comments=True, encoding="UTF-8", no_network=True, recover=True)
        root = etree.XML(self.text, parser=parser)
        self.tree = etree.XPathElementEvaluator(root)

        print(f"test: { self.tree('/*') }")
 

В моем модульном тестировании это выводит следующее:

 test_parse (test_converter.TestConverter) ... test: [<Element {http://www.ivoa.net/xml/VOTable/v1.3}VOTABLE at 0x7fa2b99a8dc0>]
 

Однако, когда я пытаюсь выполнить запрос, как показано ниже, в результате я получаю пустой список:

 print(f"test: { self.tree('/VOTABLE*') }")
 

Я попытался добавить пространство имен к VOTABLE, как показано ниже, но тоже безрезультатно:

 print(f"test: { self.tree('/{http://www.ivoa.net/xml/VOTable/v1.3}VOTABLE*') }")
 

Кто-нибудь может сказать мне, какую ошибку новичка я совершаю?

Пример данных:

 <VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.ivoa.net/xml/VOTable/v1.3"
  xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3">
 <DESCRIPTION>
   VizieR Astronomical Server vizier.u-strasbg.fr
    Date: 2020-11-07T11:43:26 [V1.99  (14-Oct-2013)]
   Explanations and Statistics of UCDs:         See LINK below
   In case of problem, please report to:    cds-question@unistra.fr
   In this version, NULL integer columns are written as an empty string
   amp;<TDamp;>amp;</TDamp;>, explicitely possible from VOTable-1.3
 </DESCRIPTION>
 <RESOURCE ID="yCat_3135" name="III/135A">
  ...
 </RESOURCE>
 ...
</VOTABLE>
 

ОБНОВЛЕНИЕ: РЕШЕНИЕ

Как только drec4s указал, что я не регистрировал пространство имен для запроса, мне удалось выяснить, что я делал неправильно. Вот рабочий блок кода:

         parser = etree.XMLParser(remove_comments=True, encoding="UTF-8", no_network=True, recover=True)
        root = etree.XML(self.text, parser=parser)
        self.tree = etree.XPathElementEvaluator(root)
        self.tree.register_namespace("n", "http://www.ivoa.net/xml/VOTable/v1.3")
        test = self.tree("/n:VOTABLE/n:DESCRIPTION/text()")
 

Ответ №1:

Вы можете использовать этот xpath метод, но вам также необходимо включить namespace в метод сопоставление:

 from lxml import etree
from io import StringIO

xmldoc =  StringIO("""
<VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.ivoa.net/xml/VOTable/v1.3"
  xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3">
 <DESCRIPTION>
   VizieR Astronomical Server vizier.u-strasbg.fr
    Date: 2020-11-07T11:43:26 [V1.99  (14-Oct-2013)]
   Explanations and Statistics of UCDs:         See LINK below
   In case of problem, please report to:    cds-question@unistra.fr
   In this version, NULL integer columns are written as an empty string
   amp;<TDamp;>amp;</TDamp;>, explicitely possible from VOTable-1.3
 </DESCRIPTION>
 <RESOURCE ID="yCat_3135" name="III/135A">
 </RESOURCE>
</VOTABLE>
""")

tree = etree.parse(xmldoc)
root = tree.getroot()
print(root.xpath('//n:DESCRIPTION', namespaces={'n': 'http://www.ivoa.net/xml/VOTable/v1.3'})[0].text)
 

Вывод:

    VizieR Astronomical Server vizier.u-strasbg.fr
    Date: 2020-11-07T11:43:26 [V1.99  (14-Oct-2013)]
   Explanations and Statistics of UCDs:         See LINK below
   In case of problem, please report to:    cds-question@unistra.fr
   In this version, NULL integer columns are written as an empty string
   <TD></TD>, explicitely possible from VOTable-1.3
 

Комментарии:

1. Спасибо, это сделало это. Поскольку я использовал XPathElementEvaluator, метода xpath() не было, но я зарегистрировал пространство имен, и оно сработало.