2014-07-24 8 views
7

Beim Analysieren von .docx Datei Inhalt in Form von XML (Word/Dokument.xml) mit BeautifulSoup4 (mit LXml installiert, wie erforderlich) Ich stieß auf ein Problem. Dieser Teil von xml:xml Parsing mit BeautifulSoup4, Namespaces Problem

... 
    <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"> 
    ... 

wird dies:

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

Selbst wenn ich Datei nur analysieren und speichern, ohne irgendwelche Änderungen. Wie folgt:

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

Oder analysieren Sie XML von Python-Konsole.

Für mich sieht es wie Namespaces, deklariert wie folgt, nicht im Stammdokument Knoten, von Parser gegessen werden.

Ist das ein Fehler oder eine Funktion? Und gibt es eine Möglichkeit, diese beim Parsing mit beautifulesoup4 zu bewahren? Oder muss ich zu etwas anderem wechseln?

UPDATE 1: wenn mit einigen regex und Ersetzen von Text ich diese Namespace-Deklarationen an die Wurzel document Knoten hinzufügen, dann beautifulsoup parst es einfach gut. Aber ich bin immer noch interessiert, ob dies ohne Modifikation von XML vor der Analyse gelöst werden kann.

AKTUALISIEREN 2: nach dem Spielen mit beautifulsoup ein bisschen, ich fand heraus, dass Namespace-Deklarationen nur beim ersten Auftreten geparst werden. Bedeutet, dass, wenn das Tag den Namespace deklariert, die untergeordneten Namespace-Deklarationen nicht analysiert werden. Unten ist ein Codebeispiel mit einer Ausgabe, um das zu veranschaulichen.

von BS4 Import 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 

Wird Ausgabe erzeugen:

============== 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> 

See, wie zunächst zwei xmls korrekt analysiert werden, während der zweite Erklärung in dritten gegessen wird.

Eigentlich betrifft dieses Problem nicht mehr docx. Und meine Frage ist auf so gerundet: Ist dieses Verhalten in beautifulsoup4 festgeschrieben, und wenn nicht, wie kann ich es dann ändern?

+2

Ich hatte Erfolg mit der Übergabe von 'lxml' an den Suppenkonstruktor anstelle von 'xml'. Nicht immer aber ... –

Antwort

0

Von der W3C-Empfehlung:

Das Präfix bietet den Namespacepräfix Teil des qualifizierten Namen und MUST mit einer Namespace URI-Referenz in einer Namespace-Deklaration in Verbindung gebracht werden.

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

Also ich denke, es das erwartete Verhalten ist: verwerfen die Namespaces nicht deklariert einige Parsing auf Dokumente ordnungsgemäß zu erlauben, die nicht die Empfehlung respektieren.