2

我正在尝试从<v:imagedata r:id="rId7" o:title="1-REN"/>带有命名空间的 Word 文档中查找所有内容xmlns:v="urn:schemas-microsoft-com:vml",但我无法弄清楚语法到底是什么。

这些文档只涵盖了非常简单的案例,并且使用了 URN 和 VML 组合,我似乎无法让我在网上看到的任何示例都能正常工作。有谁碰巧知道它是什么?

我正在尝试做这样的事情:

namespace = {'v': "urn:schemas-microsoft-com:vml"}

results = ET.fromstring(xml).findall("imagedata", namespace)
for image_id in results:
    print(image_id)

编辑:@aneroid 写的是 1000% 的正确答案并且非常有帮助。你应该赞成它。也就是说,在了解了所有这些之后 - 我选择了 BS4 答案,因为它完全按照我的需要在两行中完成了整个工作。如果您实际上并不关心名称空间,那么它似乎更容易。

4

3 回答 3

8

使用Python 3.8中的 ElementTree ,您可以简单地为命名空间使用通配符 ( {*}):

results = ET.fromstring(xml).findall(".//{*}imagedata") 

注意.//部分,这意味着搜索整个文档(所有后代)。

于 2020-05-31T14:30:43.163 回答
2

ET.findall()BS4.find_all()

  • findall()默认情况下,ElementTree不是递归的*。它只会找到提供的节点的直接子节点。因此,在您的情况下,它仅在根元素下直接搜索图像节点。
    • *根据下面mzjn 的评论match,为参数(标记或路径)添加前缀将在树中的任何位置".//"搜索该节点,因为它支持 XPath 的.
  • BeautifulSoupfind_all() 搜索所有后代。因此它会在树中的任何位置搜索“imagedata”节点。
  • 但是,ElementTree.iter()确实搜索所有后代。使用文档中的“使用命名空间”示例

    >>> for char in root.iter('{http://characters.example.com}character'):
    ...     print(' |-->', char.text)
    ...
     |--> Lancelot
     |--> Archie Leach
     |--> Sir Robin
     |--> Gunther
     |--> Commander Clement
    
  • 可悲的是,ET.iterfind()它使用命名空间作为 dict(如 ET.findall),也不会搜索 descendants ,默认情况下只搜索直接子代*。就像 ET.findall。除了''标签中的空字符串如何在命名空间中被处理,一个返回一个列表而另一个返回一个迭代器,我不能说ET.findalland之间存在有意义的区别ET.iterfind
    • *如上ET.findall(),前缀".//"使其搜索整个树(与任何节点匹配)。

当您使用带有 ET 的名称空间时,您仍然需要带有标签的名称空间名称。结果行应该是:

namespace = {'v': "urn:schemas-microsoft-com:vml"}
results = ET.fromstring(xml).findall("v:imagedata", namespace)  # note the 'v:'

此外,'v'不需要是 a 'v',如果需要,您可以将其更改为更有意义的内容:

namespace = {'image': "urn:schemas-microsoft-com:vml"}
results = ET.fromstring(xml).findall("image:imagedata", namespace)

当然,如果它们不是根的直接子元素,这仍然不一定会为您提供所有 imagedata 元素。为此,您需要创建一个递归函数来为您执行此操作。有关如何查看此答案的信息请注意,虽然该答案进行递归搜索,但如果后代深度太深,您可能会达到 Python 的递归限制。

要获取树中任意位置的所有 imagedata 元素,请使用".//"前缀:

results = ET.fromstring(xml).findall(".//v:imagedata", namespace)
于 2020-05-31T03:20:33.937 回答
1

我打算让这个问题保持开放,但我目前使用的解决方法是使用 BeautifulSoup,它很乐意接受v:语法。

soup = BeautifulSoup(xml, "lxml")

results = soup.find_all("v:imagedata")
于 2020-05-31T01:40:04.443 回答