【问题标题】:Import XML namespace in python在 python 中导入 XML 命名空间
【发布时间】:2021-10-03 02:36:27
【问题描述】:

我完全是编码新手,我学习 IT,并且有一个学校项目,我必须在其中将 .txt 文件转换为 XML 文件。我已经设法创建了一棵树和子元素,但必须在代码中放置一些 XML 命名空间。因为最终的 XML 文件必须在一个程序中打开,该程序会为您提供信息表等等。但如果没有来自 XML 命名空间的方案,它不会打开任何东西。有人可以帮助我如何将 .xsd 放入我的代码中吗?

这是方案: http://www.pufbih.ba/images/stories/epp_docs/PaketniUvozObrazaca_V1_0.xsd

必须创建的 XML 文件示例: http://www.pufbih.ba/images/stories/epp_docs/4200575050089_1022.xml

在第一行 a 有我必须输入的方案:“urn:PaketniUvozObrazaca_V1_0.xsd”

这是到目前为止创建的代码:

import xml.etree.ElementTree as xml

def GenerateXML(GIP1022):
root=xml.Element("PaketniUvozObrazaca")
p1=xml.Element("PodaciOPoslodavcu")
root.append(p1)

jib=xml.SubElement(p1,"JIBPoslodavca")
jib.text="4254160150005"
pos=xml.SubElement(p1,"NazivPoslodavca")
pos.text="MOJATVRTKA d.o.o. ORAŠJE"
zah=xml.SubElement(p1,"BrojZahtjeva")
zah.text="8"
datz=xml.SubElement(p1,"DatumPodnosenja")
datz.text="2021-01-01"

tree=xml.ElementTree(root)
with open(GIP1022,"wb") as files:
    tree.write(files)

if __name__=="__main__":
GenerateXML("primjer.xml")

【问题讨论】:

    标签: python xml elementtree xml-namespaces


    【解决方案1】:

    official documentation 对于如何在 ElementTree 中使用命名空间并不十分明确,但它的核心是 ElementTree 采用了一种非常基本的(ist)方法:elementtree 不使用命名空间前缀/别名,而是使用 @987654322 @。

    例如

    <bar xmlns="foo">
    

    <x:bar xmlns:x="foo">
    

    foo 命名空间中的元素 bar)将被写入

    {foo}bar
    
    >>> tostring(Element('{foo}bar'), encoding='unicode')
    '<ns0:bar xmlns:ns0="foo" />'
    

    或者(有时更方便创作和操作)您可以使用QName objects,它可以采用 Clark 的符号标记名称,也可以分别采用命名空间和标记名称:

    >>> tostring(Element(QName('foo', 'bar')), encoding='unicode')
    '<ns0:bar xmlns:ns0="foo" />'
    

    因此,虽然 ElementTree 本身没有命名空间对象,但您可以像这样创建命名空间对象,可能通过部分应用 QName 的助手:

    >>> root = Element(ns("PaketniUvozObrazaca"))
    >>> SubElement(root, ns("PodaciOPoslodavcu"))
    <Element <QName '{urn:PaketniUvozObrazaca_V1_0.xsd}PodaciOPoslodavcu'> at 0x7f502481bdb0>
    >>> tostring(root, encoding='unicode')
    '<ns0:PaketniUvozObrazaca xmlns:ns0="urn:PaketniUvozObrazaca_V1_0.xsd"><ns0:PodaciOPoslodavcu /></ns0:PaketniUvozObrazaca>'
    

    这里有几个重要的考虑因素:

    首先,当序列化是任意的时,您可以看到前缀,这与 ElementTree 对 XML 的原教旨主义方法一致(前缀 应该 无关紧要),但它已经增长了一个“register_namespace” 全局 允许注册特定前缀的函数:

    >>> register_namespace('xxx', 'urn:PaketniUvozObrazaca_V1_0.xsd')
    >>> tostring(root, encoding='unicode')
    '<xxx:PaketniUvozObrazaca xmlns:xxx="urn:PaketniUvozObrazaca_V1_0.xsd"><xxx:PodaciOPoslodavcu /></xxx:PaketniUvozObrazaca>'
    

    您还可以将单个 default_namespace 传递给(某些)序列化函数来指定默认命名空间:

    >>> tostring(root, encoding='unicode', default_namespace='urn:PaketniUvozObrazaca_V1_0.xsd')
    '<PaketniUvozObrazaca xmlns="urn:PaketniUvozObrazaca_V1_0.xsd"><PodaciOPoslodavcu /></PaketniUvozObrazaca>'
    

    第二个可能更大的问题是 ElementTree 不支持验证

    Python 标准库不支持任何验证解析器或树构建器,无论是 DTD、rng、xml 模式还是任何东西。不是默认的,也不是可选的。

    lxml 可能是支持验证(多种类型的模式)的主要替代方案,其核心 API 遵循 ElementTree,但以多种方式和方向对其进行了扩展(包括更精确的命名空间前缀支持和前缀往返)。但即便如此,验证(AFAIK)大多是明确的,至少在生成/序列化文档时是这样。

    【讨论】:

    • 感谢您的快速回复,事实上,这个答案对我来说有点难(高级),但我会尽力理解它。 xD
    【解决方案2】:

    您想要的是将默认命名空间声明 (xmlns="urn:PaketniUvozObrazaca_V1_0.xsd") 添加到根元素。我已经编辑了问题中的代码,以向您展示如何做到这一点。

    import xml.etree.ElementTree as ET
    
    def GenerateXML(GIP1022): 
        # Create the PaketniUvozObrazaca root element in the urn:PaketniUvozObrazaca_V1_0.xsd namespace 
        root = ET.Element("{urn:PaketniUvozObrazaca_V1_0.xsd}PaketniUvozObrazaca")
    
        # Add subelements
        p1 = ET.Element("PodaciOPoslodavcu")
        root.append(p1)
    
        jib = ET.SubElement(p1,"JIBPoslodavca")
        jib.text = "4254160150005"
        pos = ET.SubElement(p1,"NazivPoslodavca")
        pos.text = "MOJATVRTKA d.o.o. ORAŠJE"
        zah = ET.SubElement(p1,"BrojZahtjeva")
        zah.text = "8"
        datz = ET.SubElement(p1,"DatumPodnosenja")
        datz.text = "2021-01-01"
    
        # Make urn:PaketniUvozObrazaca_V1_0.xsd the default namespace (no prefix)
        ET.register_namespace("", "urn:PaketniUvozObrazaca_V1_0.xsd")
    
        # Prettify output (requires Python 3.9)
        ET.indent(root)
    
        tree = ET.ElementTree(root)
    
        with open(GIP1022,"wb") as files:
            tree.write(files)
    
    if __name__=="__main__":
        GenerateXML("primjer.xml")
    

    primjer.xml的内容:

    <PaketniUvozObrazaca xmlns="urn:PaketniUvozObrazaca_V1_0.xsd">
      <PodaciOPoslodavcu>
        <JIBPoslodavca>4254160150005</JIBPoslodavca>
        <NazivPoslodavca>MOJATVRTKA d.o.o. ORA&#352;JE</NazivPoslodavca>
        <BrojZahtjeva>8</BrojZahtjeva>
        <DatumPodnosenja>2021-01-01</DatumPodnosenja>
      </PodaciOPoslodavcu>
    </PaketniUvozObrazaca>
    

    请注意,只有根元素显式绑定到代码中的命名空间。添加子元素时,它们不需要位于命名空间中。最终结果是一个 XML 文档 (primjer.xml),其中所有元素都属于同一个默认命名空间。

    以上方法并不是在命名空间中创建元素的唯一方法。例如,可以使用QName 类代替{namespace-uri}name 表示法。见https://stackoverflow.com/a/58678592/407651

    【讨论】:

    • 很棒,非常感谢!!!这解决了我的问题!!!我必须使用该软件来读取 xml 文件,读取它并创建一个空表。现在我必须编写 xml 文件的其余部分,以确定是否所有元素都会出现在软件的表格中。
    【解决方案3】:

    tree.write() 方法采用 default_namespace 参数。

    如果您将该行更改为以下内容会发生什么?

    tree.write(files, default_namespace="urn:PaketniUvozObrazaca_V1_0.xsd")
    

    【讨论】:

    • 对不起,我的回复晚了,感谢您的帮助。如果我理解你很好,这就是我得到这种错误的原因:imgur.com/a/LK0gMrr
    • 在 SO(或者实际上是 Google)中搜索 ValueError: cannot use non-qualified names with default_namespace option 会产生 this answer。 @Andomar 做的事情和你不一样,但是把 xml.register_namespace("", "urn:PaketniUvozObrazaca_V1_0.xsd") 放在你的 root=xml.Element("PaketniUvozObrazaca") 之前有用吗?
    • 我试过了,没有出错。但这并没有解决我的问题,因为这并没有将架构放在我的 xml 中,因为在此之后我的 xml 锁定就像这样(imgur.com/a/cWhSSya)。您在我的 xml 中没有看到我写的链接,它必须与左侧文档中的相同,我的软件可以读取我创建的 xml。我现在正在尝试使用 lxml 包来放置 xsd,但是当然,这很麻烦....
    猜你喜欢
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    相关资源
    最近更新 更多