kzen.dev
  • Întrebări
  • Tag-uri
  • Utilizatori
Notificări
Recompense
Înregistrare
După înregistrare, veți primi notificări despre răspunsurile și comentariile la întrebările DVS.
Logare
Dacă aveţi deja un cont, autentificaţi-vă pentru a verifica notificările noi.
Aici vor fi recompensele pentru întrebările, răspunsurile și comentariile adăugate sau modificate.
Mai mult
Sursă
Editează
 KevinLeng
KevinLeng
Question

Python ElementTree modulul: Cum să ignore nume de fișiere XML pentru a localiza element de potrivire atunci când se utilizează metoda "a găsi", "findall"

Vreau să folosesc metoda de "findall" pentru a localiza unele elemente de sursă fișier xml în ElementTree module.

Cu toate acestea, sursa fișier xml (test.xml) are nume. Am trunchia o parte din fișier xml ca probă:

<?xml version="1.0" encoding="iso-8859-1"?>
<XML_HEADER xmlns="http://www.test.com">
    <TYPE>Updates</TYPE>
    <DATE>9/26/2012 10:30:34 AM</DATE>
    <COPYRIGHT_NOTICE>All Rights Reserved.</COPYRIGHT_NOTICE>
    <LICENSE>newlicense.htm</LICENSE>
    <DEAL_LEVEL>
        <PAID_OFF>N</PAID_OFF>
        </DEAL_LEVEL>
</XML_HEADER>

Mostră de cod python este mai jos:

from xml.etree import ElementTree as ET
tree = ET.parse(r"test.xml")
el1 = tree.findall("DEAL_LEVEL/PAID_OFF") # Return None
el2 = tree.findall("{http://www.test.com}DEAL_LEVEL/{http://www.test.com}PAID_OFF") # Return <Element '{http://www.test.com}DEAL_LEVEL/PAID_OFF' at 0xb78b90>

Deși se poate merge, pentru că nu există un spațiu de nume "{http://www.test.com}", a's foarte incomod pentru a adăuga un nume în fața fiecare etichetă.

Cum pot ignora nume atunci când se utilizează metoda de "găsi", "findall" și așa mai departe?

118 2012-11-16T07:53:17+00:00 9
Programare
namespaces
python
find
elementtree
findall
 nonagon
nonagon
18 septembrie 2014 в 7:37
2014-09-18T19:37:36+00:00
Mai mult
Sursă
Editează
#17739384

În loc de a modifica documentul XML în sine, l's cel mai bun pentru a analiza și apoi modifica tag-uri în consecință. În acest fel puteți gestiona mai multe spații de nume și nume pseudonime:

from io import StringIO  # for Python 2 import from StringIO instead
import xml.etree.ElementTree as ET

# instead of ET.fromstring(xml)
it = ET.iterparse(StringIO(xml))
for _, el in it:
    prefix, has_namespace, postfix = el.tag.partition('}')
    if has_namespace:
        el.tag = postfix  # strip all namespaces
root = it.root

Aceasta se bazează pe discuții aici: http://bugs.python.org/issue18304

 nonagon
nonagon
Răspuns editat 21 octombrie 2019 в 2:28
50
0
 user2212280
user2212280
26 martie 2013 в 3:44
2013-03-26T15:44:24+00:00
Mai mult
Sursă
Editează
#17739381

Dacă eliminați atributul xmlns din xml înainte de parsare atunci nu va't fi un nume precedat la fiecare etichetă în copac.

import re

xmlstring = re.sub(' xmlns="[^"]+"', '', xmlstring, count=1)
 david.barkhuizen
david.barkhuizen
Răspuns editat 24 septembrie 2014 в 5:21
48
0
 wimous
wimous
20 noiembrie 2013 в 7:07
2013-11-20T19:07:52+00:00
Mai mult
Sursă
Editează
#17739383

Răspunsurile atât de departe în mod explicit a pus nume valoare în script-ul. Pentru o mai generic soluție, mai degrabă aș extrage nume din xml:

import re
def get_namespace(element):
  m = re.match('\{.*\}', element.tag)
  return m.group(0) if m else ''

Și de a folosi în a găsi metoda:

namespace = get_namespace(tree.getroot())
print tree.find('./{0}parent/{0}version'.format(namespace)).text
Pierluigi Vernetto
Pierluigi Vernetto
Răspuns editat 30 ianuarie 2018 в 4:42
18
0
 barny
barny
30 noiembrie 2015 в 11:21
2015-11-30T11:21:06+00:00
Mai mult
Sursă
Editează
#17739385

Aici's o extensie a nonagon's-a răspuns, care, de asemenea, benzi de spații de nume pe atribute:

from StringIO import StringIO
import xml.etree.ElementTree as ET

# instead of ET.fromstring(xml)
it = ET.iterparse(StringIO(xml))
for _, el in it:
    if '}' in el.tag:
        el.tag = el.tag.split('}', 1)[1]  # strip all namespaces
    for at in el.attrib.keys(): # strip namespaces of attributes too
        if '}' in at:
            newat = at.split('}', 1)[1]
            el.attrib[newat] = el.attrib[at]
            del el.attrib[at]
root = it.root
14
0
 lijat
lijat
12 decembrie 2018 в 7:52
2018-12-12T07:52:21+00:00
Mai mult
Sursă
Editează
#17739387

Îmbunătățirea răspunde de ericspod:

În loc de a schimba analiza modul global putem încheia într-un obiect sprijinirea cu construct.

from xml.parsers import expat

class DisableXmlNamespaces:
    def __enter__(self):
            self.oldcreate = expat.ParserCreate
            expat.ParserCreate = lambda encoding, sep: self.oldcreate(encoding, None)
    def __exit__(self, type, value, traceback):
            expat.ParserCreate = self.oldcreate

Acest lucru poate fi apoi utilizat după cum urmează

import xml.etree.ElementTree as ET
with DisableXmlNamespaces():
     tree = ET.parse("test.xml")

Frumusetea acestui mod este că ea nu se schimbă comportamentul de legătură, cod afara cu bloc. Am sfârșit prin a crea acest lucru după ce erori în alte biblioteci după utilizarea versiunea de ericspod care, de asemenea, s-a întâmplat să utilizați expat.

9
0
 tzp
tzp
8 octombrie 2013 в 10:18
2013-10-08T10:18:17+00:00
Mai mult
Sursă
Editează
#17739382

Puteți utiliza elegant șir de formatare a construi la fel de bine:

ns='http://www.test.com'
el2 = tree.findall("{%s}DEAL_LEVEL/{%s}PAID_OFF" %(ns,ns))

sau, daca're sigur că PAID_OFF apare doar într-un singur nivel în arbore:

el2 = tree.findall(".//{%s}PAID_OFF" % ns)
4
0
 ericspod
ericspod
19 ianuarie 2018 в 3:56
2018-01-19T15:56:47+00:00
Mai mult
Sursă
Editează
#17739386

Daca're folosind ElementTree "și nu" cElementTree poți forța Expat să ignore nume de prelucrare prin înlocuireaParserCreate()`:

from xml.parsers import expat
oldcreate = expat.ParserCreate
expat.ParserCreate = lambda encoding, sep: oldcreate(encoding, None)

ElementTree încearcă să folosească Expat de asteptare ParserCreate() dar nu oferă opțiunea de a nu oferi un spațiu de nume separator șir, codul de mai sus va face ca acesta să fie ignorat, dar să fie avertizat, acest lucru ar putea rezolva alte lucruri.

2
0
 z33k
z33k
13 august 2019 в 9:00
2019-08-13T09:00:10+00:00
Mai mult
Sursă
Editează
#17739389

Las's combina nonagon's a răspunde cu mzjn's a răspunde la o întrebare legată de:

def parse_xml(xml_path: Path) -> Tuple[ET.Element, Dict[str, str]]:
    xml_iter = ET.iterparse(xml_path, events=["start-ns"])
    xml_namespaces = dict(prefix_namespace_pair for _, prefix_namespace_pair in xml_iter)
    return xml_iter.root, xml_namespaces

Folosind această funcție, avem:

  1. Creați un iterator pentru a obține ambele spații de nume și analizat un copac obiect.

  2. Repeta peste creat iterator pentru a obține spații de nume dict că putem mai târziu trece în fiecare găsim () " sau " findall()` sun ca dată de iMom0.

  3. Reveni analizat copac's element rădăcină obiect și spații de nume.

Cred că aceasta este cea mai bună abordare în jurul ca acolo's nici o manipulare, fie de o sursă XML sau care rezultă analizat xml.etree.ElementTree ieșire un fel de implicat.

Am'd place, de asemenea, de credit barny's a răspunde, cu furnizarea de o piesă esențială a puzzle-ului (pe care le puteți obține analizat rădăcină de iterator). Până ca de fapt am traversat XML tree de doua ori la cererea mea (o dată pentru a obține spații de nume, al doilea pentru o rădăcină).

 z33k
z33k
Răspuns editat 14 septembrie 2019 в 7:52
1
0
 est
est
20 martie 2019 в 1:11
2019-03-20T13:11:31+00:00
Mai mult
Sursă
Editează
#17739388

S-ar putea să fie târziu pentru asta, dar nu cred ca re.sub este o soluție bună.

Cu toate acestea rescrie xml.interpretoare.expat nu funcționează pentru Python 3.x versiuni,

Principalul vinovat este xml/etree/ElementTree.py se vedea partea de jos a codului sursă

# Import the C accelerators
try:
    # Element is going to be shadowed by the C implementation. We need to keep
    # the Python version of it accessible for some "creative" by external code
    # (see tests)
    _Element_Py = Element

    # Element, SubElement, ParseError, TreeBuilder, XMLParser
    from _elementtree import *
except ImportError:
    pass

Ceea ce e cam trist.

Soluția este de a scăpa de ea în primul rând.

import _elementtree
try:
    del _elementtree.XMLParser
except AttributeError:
    # in case deleted twice
    pass
else:
    from xml.parsers import expat  # NOQA: F811
    oldcreate = expat.ParserCreate
    expat.ParserCreate = lambda encoding, sep: oldcreate(encoding, None)

Testat pe Python 3.6.

Încercați "încerca" declarație este util în cazul în care undeva în codul de reincarcare sau importați un modul de două ori veți obține unele erori ciudate ca

  • maxim recursivitate adâncime depășit
  • AttributeError: XMLParser

btw blestemat pomul codul sursa arata foarte murdar.

 est
est
Răspuns editat 20 martie 2019 в 1:19
0
0
Comunități asemănătoare 1
Python România
Python România
125 utilizatori
Comunitatea pasionaților de Python din România.
Deschide telegram
Adăugati o întrebare
Categorii
Toate
Tehnologii
Cultură
Viață / Artă
Stiință
Profesii
Afaceri
Utilizatori
Toate
Nou
Populare
1
工藤 芳則
Înregistrat 6 zile în urmă
2
Ирина Беляева
Înregistrat 1 săptămână în urmă
3
Darya Arsenyeva
Înregistrat 1 săptămână în urmă
4
anyta nuam-nuam (LapuSiK)
Înregistrat 1 săptămână în urmă
5
Shuhratjon Imomkulov
Înregistrat 1 săptămână în urmă
ID
JA
KO
RO
RU
© kzen.dev 2023
Sursă
stackoverflow.com
în cadrul licenței cc by-sa 3.0 cu atribuire