2010-09-24 3 views
7

Python elementTree scheint mit Namespaces nicht verwendbar zu sein. Was sind meine Alternativen? BeautifulSoup ist ziemlich Müll mit Namensräumen auch. Ich möchte sie nicht ausstreifen.Guter Python-XML-Parser für die Arbeit mit schweren Namespace-Dokumenten

Beispiele, wie eine bestimmte Python-Bibliothek bekommt Namespace-Elemente und ihre Sammlungen sind alle +1.

Bearbeiten: Könnten Sie Code zur Verfügung stellen, um mit diesem realen Anwendungsfall mit Ihrer bevorzugten Bibliothek umzugehen?

Wie würden Sie gehen über Strings 'Zeilenumbruch', '2.6' und eine Liste [ 'PYTHON', 'XML', 'XML-Namespaces']

<?xml version="1.0" encoding="UTF-8"?> 
<zs:searchRetrieveResponse 
    xmlns="http://unilexicon.com/vocabularies/" 
    xmlns:zs="http://www.loc.gov/zing/srw/" 
    xmlns:dc="http://purl.org/dc/elements/1.1/" 
    xmlns:lom="http://ltsc.ieee.org/xsd/LOM"> 
    <zs:records> 
     <zs:record> 
      <zs:recordData> 
       <srw_dc:dc xmlns:srw_dc="info:srw/schema/1/dc-schema"> 
        <name>Line Break</name> 
        <dc:title>Processing XML namespaces using Python</dc:title> 
        <dc:description>How to get contents string from an element, 
         how to get a collection in a list...</dc:description> 
        <lom:metaMetadata> 
         <lom:identifier> 
          <lom:catalog>Python</lom:catalog> 
          <lom:entry>2.6</lom:entry> 
         </lom:identifier> 
        </lom:metaMetadata> 
        <lom:classification> 
         <lom:taxonPath> 
          <lom:taxon> 
           <lom:id>PYTHON</lom:id> 
          </lom:taxon> 
         </lom:taxonPath> 
        </lom:classification> 
        <lom:classification> 
         <lom:taxonPath> 
          <lom:taxon> 
           <lom:id>XML</lom:id> 
          </lom:taxon> 
         </lom:taxonPath> 
        </lom:classification> 
        <lom:classification> 
         <lom:taxonPath> 
          <lom:taxon> 
           <lom:id>XML-NAMESPACES</lom:id> 
          </lom:taxon> 
         </lom:taxonPath> 
        </lom:classification> 
       </srw_dc:dc> 
      </zs:recordData> 
     </zs:record> 
     <!-- ... more records ... --> 
    </zs:records> 
</zs:searchRetrieveResponse> 
+1

ich die Meta-Art Ihrer MWE lieben. –

+0

Die Verwendung relevanter Schlüsselwörter im Beispielcode bedeutet, dass mehr Nutzer die Fragen und Antworten finden können. –

Antwort

12

lxml ist der Namespace-aware.

>>> from lxml import etree 
>>> et = etree.XML("""<root xmlns="foo" xmlns:stuff="bar"><bar><stuff:baz /></bar></root>""") 
>>> etree.tostring(et, encoding=str) # encoding=str only needed in Python 3, to avoid getting bytes 
'<root xmlns="foo" xmlns:stuff="bar"><bar><stuff:baz/></bar></root>' 
>>> et.xpath("f:bar", namespaces={"b":"bar", "f": "foo"}) 
[<Element {foo}bar at ...>] 

Edit: Auf Ihrem Beispiel:

from lxml import etree 

# remove the b prefix in Python 2 
# needed in python 3 because 
# "Unicode strings with encoding declaration are not supported." 
et = etree.XML(b"""...""") 

ns = { 
    'lom': 'http://ltsc.ieee.org/xsd/LOM', 
    'zs': 'http://www.loc.gov/zing/srw/', 
    'dc': 'http://purl.org/dc/elements/1.1/', 
    'voc': 'http://www.schooletc.co.uk/vocabularies/', 
    'srw_dc': 'info:srw/schema/1/dc-schema' 
} 

# according to docs, .xpath returns always lists when querying for elements 
# .find returns one element, but only supports a subset of XPath 
record = et.xpath("zs:records/zs:record", namespaces=ns)[0] 
# in this example, we know there's only one record 
# but else, you should apply the following to all elements the above returns 

name = record.xpath("//voc:name", namespaces=ns)[0].text 
print("name:", name) 

lom_entry = record.xpath("zs:recordData/srw_dc:dc/" 
         "lom:metaMetadata/lom:identifier/" 
         "lom:entry", 
         namespaces=ns)[0].text 

print('lom_entry:', lom_entry) 

lom_ids = [id.text for id in 
      record.xpath("zs:recordData/srw_dc:dc/" 
         "lom:classification/lom:taxonPath/" 
         "lom:taxon/lom:id", 
         namespaces=ns)] 

print("lom_ids:", lom_ids) 

Ausgang:

name: Frank Malina 
lom_entry: 2.6 
lom_ids: ['PYTHON', 'XML', 'XML-NAMESPACES'] 
+2

+1 lxml ist das einzige Python-Tool/Paket, das Sie jemals für xml/xslt/xpath-ähnliche Aufgaben benötigen – snapshoe

+0

Edit: Wie würden Sie das mitgelieferte Beispiel codieren? Der Mangel an Rezepten im Internet für diese Art von LXML-Arbeit ist erschreckend. Im Moment habe ich die Namensräume entfernt und mit BeautifulSoup gequert. Dies ist auf mehreren Ebenen suboptimal. –

+0

@Frank Malina: XPath ist nicht lxml-spezifisch, es gibt einige nutzbare Ressourcen auf XPath im Web. Aber ich werde einen Stich machen ... – delnan

0

libxml (http://xmlsoft.org/) Best, schneller lib für das Parsen von xML. Es gibt eine Implementierung für Python.

+4

lxml aus codespeak umschließt und verwendet libxml – snapshoe