【问题标题】:How to find XML element by tag in Python如何在 Python 中按标签查找 XML 元素
【发布时间】:2021-09-29 13:28:31
【问题描述】:

我无法在 Python 中识别正确的元素。我真正想看到的是 recently-used.xbel 中最新访问的文件。因此,我想遍历每个文件以找到具有最新 modified 或最新 visited 的文件 这就是 XML 文件的样子。

<?xml version="1.0" encoding="UTF-8"?>
<xbel version="1.0"
      xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks"
      xmlns:mime="http://www.freedesktop.org/standards/shared-mime-info"
>
  <bookmark href="file:///tmp/google-chrome-stable_current_amd64.deb" added="2021-09-14T12:09:05Z" modified="2021-09-14T12:09:05Z" visited="2021-09-15T09:12:13Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/vnd.debian.binary-package"/>
        <bookmark:applications>
          <bookmark:application name="Firefox" exec="&apos;firefox %u&apos;" modified="2021-09-14T12:09:05Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/Git/testprog" added="2021-09-15T09:12:13Z" modified="2021-09-15T09:12:13Z" visited="2021-09-15T09:12:13Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="inode/directory"/>
        <bookmark:applications>
          <bookmark:application name="code" exec="&apos;code %u&apos;" modified="2021-09-15T09:12:13Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/.local/share/recently-used.xbel" added="2021-09-15T09:51:57Z" modified="2021-09-15T09:51:57Z" visited="2021-09-15T09:51:57Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/x-xbel"/>
        <bookmark:applications>
          <bookmark:application name="code" exec="&apos;code %u&apos;" modified="2021-09-15T09:51:57Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///tmp/slack-desktop-4.19.2-amd64.deb" added="2021-09-15T11:45:49Z" modified="2021-09-15T11:45:49Z" visited="2021-09-16T13:26:26Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/vnd.debian.binary-package"/>
        <bookmark:applications>
          <bookmark:application name="Firefox" exec="&apos;firefox %u&apos;" modified="2021-09-15T11:45:49Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/Downloads/google-chrome-stable_current_amd64.deb" added="2021-09-15T11:52:39Z" modified="2021-09-15T11:52:39Z" visited="2021-09-16T13:26:26Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/vnd.debian.binary-package"/>
        <bookmark:applications>
          <bookmark:application name="Firefox" exec="&apos;firefox %u&apos;" modified="2021-09-15T11:52:39Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/Documents/libretest" added="2021-09-15T11:58:53Z" modified="2021-09-15T11:58:53Z" visited="2021-09-16T13:26:26Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/octet-stream"/>
        <bookmark:applications>
          <bookmark:application name="LibreOffice 6.4" exec="&apos;soffice %u&apos;" modified="2021-09-15T11:58:53Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/Documents/libretest.odt" added="2021-09-15T11:58:53Z" modified="2021-09-15T15:42:04Z" visited="2021-09-16T13:26:26Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/vnd.oasis.opendocument.text"/>
        <bookmark:applications>
          <bookmark:application name="LibreOffice 6.4" exec="&apos;soffice %u&apos;" modified="2021-09-15T15:42:04Z" count="12"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
  <bookmark href="file:///home/test/Git/node-socket" added="2021-09-16T13:26:25Z" modified="2021-09-16T13:26:49Z" visited="2021-09-16T13:26:26Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="inode/directory"/>
        <bookmark:applications>
          <bookmark:application name="code" exec="&apos;code %u&apos;" modified="2021-09-16T13:26:49Z" count="2"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
</xbel>

在我的代码中,我试图访问bookmark:applications,但没有成功。

    home = str(Path.home())
    root = ET.parse(home + '/.local/share/recently-used.xbel').getroot()
    print(root)
    print('lower')
    for bookmark in root.iter('bookmark'):
        print(bookmark)
        for applications in bookmark.find('applications'):
            print(applications)

访问bookmark:applications 并找到上次访问的正确方法是什么?

【问题讨论】:

  • 尝试使用xmltodict
  • bookmark:applications 元素绑定到http://www.freedesktop.org/standards/desktop-bookmarks 命名空间(通过xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks")。见docs.python.org/3/library/…
  • 如果您只需要最后修改的书签信息,那么您可以使用书签标签的修改属性来做到这一点,因为书签的修改属性和书签的修改属性:应用程序都具有相同的值。

标签: python xml ubuntu xpath


【解决方案1】:

这对于访问书签很有用:应用程序和数据框将帮助您获取最新访问/修改的带有应用程序名称的书签。

import xml.etree.ElementTree as ET
import pandas as pd

root = ET.parse('/content/sample.xml').getroot()
lst = []

for bookmark in bookmarklist:
  bookmark_lst = []
  print(bookmark.attrib)
  bookmark_lst.append(bookmark.attrib['href'])
  bookmark_lst.append(bookmark.attrib['modified'])
  bookmark_lst.append(bookmark.attrib['visited'])
  for ele in list(bookmark.iter()) :
    if 'application' in ele.tag:
      if 'name' in ele.attrib:
        bookmark_lst.append(ele.attrib['name'])
  lst.append(bookmark_lst)

df = pd.DataFrame(lst,columns ['href','modified','visited','application_name'])

df['modified'] = pd.to_datetime(df['modified'])
df['visited'] = pd.to_datetime(df['visited'])

least_recent_date = df['visited'].min()
most_recent_date = df['visited'].max()

【讨论】:

  • 问题中的问题是什么?不要只是发布没有解释的代码。问题中没有关于熊猫的内容。
  • 我实际上想要元素和他的所有属性。不仅是日期。这只会显示最旧和最新的日期。我想获取日期最高的元素并检查其他属性。
  • 我在熊猫方面做得很好。列未定义。
【解决方案2】:
from lxml import etree

NS = {"n": "http://www.freedesktop.org/standards/desktop-bookmarks"}

root = etree.parse("book.xml")
bookmarks = root.xpath("//bookmark")
most_recent_bookmark = max(
    bookmarks,
    key=lambda bmark: bmark.xpath(
        "string(.//n:application/@modified)",
        namespaces=NS,
    ),
)

print("Most recent href: " + most_recent_bookmark.xpath("string(@href)"))
print(
    "Most recent modified: "
    + most_recent_bookmark.xpath("string(.//n:application/@modified)", namespaces=NS)
)

输出:

Most recent href: file:///home/test/Git/node-socket
Most recent modified: 2021-09-16T13:26:49Z

您遇到的问题是指定由原始 xml 中的 bookmark: 和代码示例中的 n: 表示的命名空间。 xpath()find()findall() 函数都允许您提供命名空间字典。

https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findall

如您所说,如果命名空间可能发生变化,您可以使用 XPath .//*[local-name() = 'application']/@modified 代替不带命名空间参数的 .//n:application/@modified。 (但是,如果看到生产者随意更改命名空间,我会感到惊讶,因为它只是要求破坏所有消耗数据的东西。url 与“应用程序”一样是节点名称的一部分。)

【讨论】:

  • 我的问题是我并不总是知道命名空间。如果它改变了我的实现将无法工作。有没有办法从文件中获取它。我不想硬编码它。
  • 我相信.//*:application/@modified 应该适当地匹配任何命名空间。等我有时间再测试。
  • 也就是说,看到命名空间任意更改,我会感到非常惊讶。
  • 重写了函数以使其更清晰,并提供了一种围绕变量命名空间的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多