【问题标题】:xml parsing with beautifulsoup4, namespaces issue用beautifulsoup4解析xml,命名空间问题
【发布时间】:2014-09-16 06:02:26
【问题描述】:

在使用beautifulsoup4(根据需要安装了lxml)以xml(word/document.xml)的形式解析.docx 文件内容时,我遇到了一个问题。这部分来自xml:

    ...
    <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
        <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
            <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
    ...

变成这样:

    ...
    <graphic>
        <graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
            <pic>
    ...

即使我只是解析文件并保存它,没有任何修改。像这样:

    from bs4 import BeautifulSoup
    soup = BeautifulSoup(open(filepath_in), 'xml')
    with open(filepath_out, "w+") as fd:
        fd.write(str(soup))

或者从python控制台解析xml。

对我来说,它看起来像命名空间,像这样声明,不在根文档节点中,被解析器吃掉。

这是错误还是功能?有没有办法在用beautifulesoup4解析时保留这些?还是我需要为此切换到其他东西?

更新 1: 如果我使用一些正则表达式和文本替换我将这些命名空间声明添加到根 document 节点,然后 beautifulsoup 解析它就好了。但是如果在解析之前不修改xml就可以解决这个问题,我仍然很感兴趣。

更新 2: 在玩了一些 beutifulsoup 之后,我发现命名空间声明仅在第一次出现时被解析。意思是如果标签声明了命名空间,那么如果它的孩子有命名空间声明,它们将不会被解析。下面是带有输出的代码示例来说明这一点。

从 bs4 导入 BeautifulSoup

xmls = []
xmls.append("""<name1:tag xmlns:name1="namespace1" xmlns:name2="namespace2">
<name2:intag>
text
</name2:intag>
</name1:tag>
""")
xmls.append("""<tag>
<name2:intag xmlns:name2="namespace2">
text
</name2:intag>
</tag>
""")
xmls.append("""<name1:tag xmlns:name1="namespace1">
<name2:intag xmlns:name2="namespace2">
text
</name2:intag>
</name1:tag>
""")
for i, xml in enumerate(xmls):
    print "============== xml {} ==============".format(i)
    soup = BeautifulSoup(xml, "xml")
    print soup

将产生输出:

============== xml 0 ==============
<?xml version="1.0" encoding="utf-8"?>
<name1:tag xmlns:name1="namespace1" xmlns:name2="namespace2">
<name2:intag>
text
</name2:intag>
</name1:tag>
============== xml 1 ==============
<?xml version="1.0" encoding="utf-8"?>
<tag>
<name2:intag xmlns:name2="namespace2">
text
</name2:intag>
</tag>
============== xml 2 ==============
<?xml version="1.0" encoding="utf-8"?>
<name1:tag xmlns:name1="namespace1">
<intag>
text
</intag>
</name1:tag>

看,如何正确解析前两个 xml,而第三个中的第二个声明被吃掉。

其实这个问题已经不涉及docx了。我的问题是这样的:这种行为是在beautifulsoup4中硬编码的,如果不是,那我该如何改变它?

【问题讨论】:

  • 我已经成功地将“lxml”传递给汤构造函数而不是“xml”。但并不总是......
  • lxml 更新了吗?
  • 有什么理由不选择使用其他专用的 xml 特定解析内置库,如 ElementTree?

标签: python xml xml-parsing beautifulsoup docx


【解决方案1】:

来自 W3C 推荐:

前缀提供了限定名称的命名空间前缀部分,并且必须与命名空间声明中的命名空间 URI 引用相关联。

https://www.w3.org/TR/REC-xml-names/#ns-qualnames

所以我认为这是预期的行为:丢弃未声明的命名空间以优雅地允许对不尊重建议的文档进行一些解析。

【讨论】:

    【解决方案2】:

    改变这一行:

    soup = BeautifulSoup(open(filepath_in), 'xml')
    

    soup = BeautifulSoup(open(filepath_in), 'lxml')
    

    soup = BeautifulSoup(open(filepath_in), 'html.parser')
    

    【讨论】:

      猜你喜欢
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 2010-11-08
      • 1970-01-01
      • 2021-05-03
      • 2014-01-10
      相关资源
      最近更新 更多