【问题标题】:How to get xpath from root to particular element in python while parsing xml解析xml时如何在python中获取从根到特定元素的xpath
【发布时间】:2018-10-07 22:54:24
【问题描述】:

我想列出 xml 中相对于它们的根的所有元素路径。例如

<A>
   <B>
     <C>Name</C>
     <D>Name</D>
   </B>
</A>

所以我想将它们列为:-

A/B/C
A/B/D

我能够使用 python 的“元素”对象解析 xml,但无法从中提取 xpath。有什么帮助吗?

【问题讨论】:

  • 是不是也应该有:A/B
  • 不只是从根目录的绝对路径

标签: python-3.x xml-parsing


【解决方案1】:

可以构造解析树的父映射,然后用它构造所需的XPath:

import xml.etree.ElementTree as parser

def get_parent_map(root):
    return {c:p for p in root.iter() for c in p}

def extract_text_info(root, original_root):
    parent_map = get_parent_map(original_root)

    for child in root:
        if child.text is not None and len(child.text.strip()) > 0:
            c = child
            arr = []
            while c != original_root:
                arr.append(c.tag)
                c = parent_map[c]
            arr.append(original_root.tag)

            print('/'.join(arr[::-1]))
            print(child.text)

        extract_text_info(child, original_root)

那么我们有

xml = """<A>
       <B>
         <C>Name</C>
         <D>Name</D>
       </B>
     </A> """

root = parser.fromstring(xml)
extract_text_info(root, root)

> A/B/C
> Name
> A/B/D
> Name

【讨论】:

    【解决方案2】:

    sample.html

    <A>
       <B>
         <C>Name1</C>
         <D>Name2</D>
       </B>
    </A>
    

    parse.py

    from bs4 import BeautifulSoup
    
    def get_root_elements(path_to_file):
        soup = BeautifulSoup(open(path_to_file), 'lxml')
        all_elements = soup.find_all()
    
        count_element_indices = [len(list(a.parents)) for a in all_elements]
    
        absolute_roots_index = min(
            (index for index, element in enumerate(count_element_indices)
                if element == max(count_element_indices)
            )
        )
    
        return all_elements[absolute_roots_index:]
    
    def get_path(element):
        to_remove = ['[document]', 'body', 'html']
        path = [element.name] + [e.name for e in element.parents if e.name not in to_remove]
    
        return ' / '.join(path[::-1])
    

    Python 外壳

    In [1]: file = 'path/to/sample.html'
    
    In [2]: run parse.py
    
    In [3]: roots = get_root_elements(file)
    
    In [4]: print(roots)
    [<c>Name1</c>, <d>Name2</d>]
    
    In [4]: for root in roots:
       ...:    print(get_path(root))
    a / b / c
    a / b / d
    

    【讨论】:

      【解决方案3】:

      我想出的方法之一是通过代码。

       import xml.etree.ElementTree as ET
      
      
      def parseXML(root,sm):
          sm = sm + "/" + root.tag[root.tag.rfind('}')+1:]
          for child in root:
            parseXML(child,sm)
          if len(list(root)) == 0:
            print(sm)
      
      tree = ET.parse('test.xml')
      root = tree.getroot()
      parseXML(root,"")
      

      不知道是否有相同的内置函数。

      【讨论】:

      • 嗯...您可以使用lxml 库吗?我的 xpath 生锈了,我相信有更好的方法,但你可以尝试类似:['/'.join(a.tag for a in el.xpath('.//ancestor::*')) for el in tree.xpath('//*[not(child::*)]')] - 例如 - 你找到所有的叶节点(那些没有孩子的) - 重新查询以获取他们的完整祖先列表,然后加入节点名称。这将为您的示例数据提供['A/B/C', 'A/B/D']。
      • 有没有办法在迭代时也获取元素内的值?但是这段代码绝对有助于迭代所有元素并获得它们的路径!漂亮……
      猜你喜欢
      • 1970-01-01
      • 2014-10-26
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 2016-09-18
      • 2020-06-19
      • 1970-01-01
      相关资源
      最近更新 更多