2017-09-20 3 views
1

Ich versuche ein Python-Skript zu schreiben, das die Datei durchläuft und den Container eines bestimmten Knotenattributs entfernt. So sieht mein Baum wie:Parsen von XML in Python und Löschen von Containern

<collection shelf="New Arrivals"> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/xyz</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/xyz</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
</collection> 

Q1

Der gesamte Behälter, wenn das Attribut des untergeordneten Knoten entfernt werden soll <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF"> gleich: /AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport

Das Skript, das ich geschrieben habe, ist:

import xml.etree.ElementTree as ET 
tree = ET.parse('autosar1.xml') 
root = tree.getroot() 
for child in root.findall(".//ECUC-NUMERICAL-PARAM-VALUE"): 
    for z in child.findall(".//DEFINITION-REF[@DEST='ECUC-BOOLEAN-PARAM-DEF']"): 
     if z.text == "/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport": 
      child.remove(z)   
tree.write('output.xml') 

Aber ich bekomme nicht die beabsichtigten Ergebnisse. Das Ergebnis bin ich immer ist:

<collection shelf="New Arrivals"> 
<ECUC-NUMERICAL-PARAM-VALUE> 
<SHORT-NAME>RTE_ABC</SHORT-NAME> 
</ECUC-NUMERICAL-PARAM-VALUE> 

<ECUC-NUMERICAL-PARAM-VALUE> 
<SHORT-NAME>RTE_ABC</SHORT-NAME> 
</ECUC-NUMERICAL-PARAM-VALUE> 

<ECUC-NUMERICAL-PARAM-VALUE> 
<SHORT-NAME>RTE_ABC</SHORT-NAME> 
</ECUC-NUMERICAL-PARAM-VALUE> 

<ECUC-NUMERICAL-PARAM-VALUE> 
<SHORT-NAME>RTE_ABC</SHORT-NAME> 
</ECUC-NUMERICAL-PARAM-VALUE> 

<ECUC-NUMERICAL-PARAM-VALUE> 
<SHORT-NAME>RTE_ABC</SHORT-NAME> 
</ECUC-NUMERICAL-PARAM-VALUE> 
</collection> 

Das Ergebnis, das ich zu bekommen:

<collection shelf="New Arrivals"> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/xyz</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
    <ECUC-NUMERICAL-PARAM-VALUE> 
    <SHORT-NAME>RTE_ABC</SHORT-NAME> 
    <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/xyz</DEFINITION-REF> 
    </ECUC-NUMERICAL-PARAM-VALUE> 
</collection> 

Q2

Statt im if Zustand des Knotenattribut von hartzucodieren ist es möglich, Nehmen Sie an, dass durch Eingabe von Benutzereingaben (in der Eingabeaufforderung) als "ComIPduCancellationSupport" (nicht das gesamte Attribut als "/AUTOSAR/EcucDefs/Com/ComConfig/ComIPdu/ComIPduCancellationSupport") die gewünschte Ausgabe erreicht wird.

Vielen Dank.

+0

Haben Sie Module von Drittanbietern wie 'lxml' verwenden? – Parfait

+0

Nein, ich habe keine Apps von Drittanbietern verwendet –

+0

Kannst du 'lxml' verwenden? – Parfait

Antwort

1

Betrachten Sie die Haftpflicht-, lxml, die funktionsreiche und leicht zu bedienende Bibliothek für in der Python XML und HTML-Verarbeitung Sprache. Sie können mit pip oder binary file für Windows installieren. Der Grund für die Empfehlung ist, dass das Modul den vollständigen W3C-konformen XPath 1.0 und XSLT 1.0 ausführen kann, wobei letztere XSLT für Sie nützlich ist.

XSLT ist eine spezielle Sprache, die XML-Dateien wie das bedingte Entfernen von Knoten transformieren kann. Speziell in XSLT führen wir Identity Transform aus (um das gesamte Dokument wie es ist zu kopieren) und führen dann eine leere Vorlage auf dem Knoten aus, den wir entfernen wollen. Beachten Sie die Verwendung von contains(), um an einer beliebigen Stelle im Text dieses Knotens nach einer Zeichenfolge zu suchen. No for Schleife oder if Logik für diesen Ansatz benötigt.

Und mit Python lxml wir ein dynamisches XSLT-Skript bauen können (was übrigens ist eine XML-Datei) aus String und übergeben Sie einen String wie Compu-METHODE-REF in . Solch eine Zeichenfolge kann von einer Benutzereingabe stammen. Beachten Sie den {0} Platzhalter für Zeichenfolge .format().

Python

import lxml.etree as et 
doc = et.parse('Input.xml') 

xsl_str='''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
             xmlns:doc="http://autosar.org/3.0.2"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <!-- IDENTITY TRANSFORM --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- EMPTY TEMPLATE --> 
    <xsl:template match="INTEGER-TYPE[descendant::COMPU-METHOD-REF/@DEST='COMPU-METHOD' and 
            contains(descendant::COMPU-METHOD-REF, '{0}')]">  
    </xsl:template> 

</xsl:stylesheet>''' 

# LOAD DYNAMIC XSL STRING (PASSING BELOW STRING INTO ABOVE) 
xsl = et.fromstring(xsl_str.format('CoolantTemp_T')) 

transform = et.XSLT(xsl) 
result = transform(doc) 

# OUTPUT TO SCREEN 
print(result)  
# OUTPUT TO FILE 
with open('output.xml', 'wb') as f: 
    f.write(result) 

Ausgabe

<?xml version="1.0"?> 
<TOP-LEVEL-PACKAGES> 
    <AR-PACKAGE> 
    <SHORT-NAME>DataType</SHORT-NAME> 
    <ELEMENTS> 
     <INTEGER-TYPE> 
     <SHORT-NAME>EngineSpeed_T</SHORT-NAME> 
     <SW-DATA-DEF-PROPS> 
      <COMPU-METHOD-REF DEST="COMPU-METHOD">/DataType/DataTypeSemantics/EngineSpeed_T</COMPU-METHOD-REF> 
     </SW-DATA-DEF-PROPS> 
     <LOWER-LIMIT INTERVAL-TYPE="CLOSED">0</LOWER-LIMIT> 
     <UPPER-LIMIT INTERVAL-TYPE="CLOSED">65535</UPPER-LIMIT> 
     </INTEGER-TYPE> 
     <INTEGER-TYPE> 
     <SHORT-NAME>VehicleSpeed_T</SHORT-NAME> 
     <SW-DATA-DEF-PROPS> 
      <COMPU-METHOD-REF DEST="COMPU-METHOD">/DataType/DataTypeSemantics/VehicleSpeed_T</COMPU-METHOD-REF> 
     </SW-DATA-DEF-PROPS> 
     <LOWER-LIMIT INTERVAL-TYPE="CLOSED">0</LOWER-LIMIT> 
     <UPPER-LIMIT INTERVAL-TYPE="CLOSED">65535</UPPER-LIMIT> 
     </INTEGER-TYPE> 
     <INTEGER-TYPE> 
     <SHORT-NAME>Percent_T</SHORT-NAME> 
     <SW-DATA-DEF-PROPS> 
      <COMPU-METHOD-REF DEST="COMPU-METHOD">/DataType/DataTypeSemantics/Percent_T</COMPU-METHOD-REF> 
     </SW-DATA-DEF-PROPS> 
     <LOWER-LIMIT INTERVAL-TYPE="CLOSED">0</LOWER-LIMIT> 
     <UPPER-LIMIT INTERVAL-TYPE="CLOSED">255</UPPER-LIMIT> 
     </INTEGER-TYPE> 
    </ELEMENTS> 
    <SUB-PACKAGES> 
     <AR-PACKAGE> 
     <SHORT-NAME>DataTypeSemantics</SHORT-NAME> 
     <ELEMENTS> 
      <COMPU-METHOD> 
      <SHORT-NAME>EngineSpeed_T</SHORT-NAME> 
      <UNIT-REF DEST="UNIT">/DataType/DataTypeUnits/rpm</UNIT-REF> 
      <COMPU-INTERNAL-TO-PHYS> 
       <COMPU-SCALES> 
       <COMPU-SCALE> 
        <COMPU-RATIONAL-COEFFS> 
        <COMPU-NUMERATOR> 
         <V>0</V> 
         <V>1</V> 
        </COMPU-NUMERATOR> 
        <COMPU-DENOMINATOR> 
         <V>8</V> 
        </COMPU-DENOMINATOR> 
        </COMPU-RATIONAL-COEFFS> 
       </COMPU-SCALE> 
       </COMPU-SCALES> 
      </COMPU-INTERNAL-TO-PHYS> 
      </COMPU-METHOD> 
      <COMPU-METHOD> 
      <SHORT-NAME>VehicleSpeed_T</SHORT-NAME> 
      <UNIT-REF DEST="UNIT">/DataType/DataTypeUnits/kph</UNIT-REF> 
      <COMPU-INTERNAL-TO-PHYS> 
       <COMPU-SCALES> 
       <COMPU-SCALE> 
        <COMPU-RATIONAL-COEFFS> 
        <COMPU-NUMERATOR> 
         <V>0</V> 
         <V>1</V> 
        </COMPU-NUMERATOR> 
        <COMPU-DENOMINATOR> 
         <V>64</V> 
        </COMPU-DENOMINATOR> 
        </COMPU-RATIONAL-COEFFS> 
       </COMPU-SCALE> 
       </COMPU-SCALES> 
      </COMPU-INTERNAL-TO-PHYS> 
      </COMPU-METHOD> 
      <COMPU-METHOD> 
      <SHORT-NAME>Percent_T</SHORT-NAME> 
      <UNIT-REF DEST="UNIT">/DataType/DataTypeUnits/Percent</UNIT-REF> 
      <COMPU-INTERNAL-TO-PHYS> 
       <COMPU-SCALES> 
       <COMPU-SCALE> 
        <COMPU-RATIONAL-COEFFS> 
        <COMPU-NUMERATOR> 
         <V>0</V> 
         <V>0.4</V> 
        </COMPU-NUMERATOR> 
        <COMPU-DENOMINATOR> 
         <V>1</V> 
        </COMPU-DENOMINATOR> 
        </COMPU-RATIONAL-COEFFS> 
       </COMPU-SCALE> 
       </COMPU-SCALES> 
      </COMPU-INTERNAL-TO-PHYS> 
      </COMPU-METHOD> 
      <COMPU-METHOD> 
      <SHORT-NAME>CoolantTemp_T</SHORT-NAME> 
      <UNIT-REF DEST="UNIT">/DataType/DataTypeUnits/DegreeC</UNIT-REF> 
      <COMPU-INTERNAL-TO-PHYS> 
       <COMPU-SCALES> 
       <COMPU-SCALE> 
        <COMPU-RATIONAL-COEFFS> 
        <COMPU-NUMERATOR> 
         <V>-40</V> 
         <V>1</V> 
        </COMPU-NUMERATOR> 
        <COMPU-DENOMINATOR> 
         <V>2</V> 
        </COMPU-DENOMINATOR> 
        </COMPU-RATIONAL-COEFFS> 
       </COMPU-SCALE> 
       </COMPU-SCALES> 
      </COMPU-INTERNAL-TO-PHYS> 
      </COMPU-METHOD> 
     </ELEMENTS> 
     </AR-PACKAGE> 
     <AR-PACKAGE> 
     <SHORT-NAME>DataTypeUnits</SHORT-NAME> 
     <ELEMENTS> 
      <UNIT> 
      <SHORT-NAME>rpm</SHORT-NAME> 
      <DISPLAY-NAME>rpm</DISPLAY-NAME> 
      </UNIT> 
      <UNIT> 
      <SHORT-NAME>kph</SHORT-NAME> 
      <DISPLAY-NAME>kph</DISPLAY-NAME> 
      </UNIT> 
      <UNIT> 
      <SHORT-NAME>Percent</SHORT-NAME> 
      <DISPLAY-NAME>Percent</DISPLAY-NAME> 
      </UNIT> 
      <UNIT> 
      <SHORT-NAME>DegreeC</SHORT-NAME> 
      <DISPLAY-NAME>DegreeC</DISPLAY-NAME> 
      </UNIT> 
     </ELEMENTS> 
     </AR-PACKAGE> 
    </SUB-PACKAGES> 
    </AR-PACKAGE> 
</TOP-LEVEL-PACKAGES> 
+0

Danke für die Antwort. Aber ich bekomme einen Fehler. Ich habe versucht, die Datei lxml-4.0.0-cp35-cp35m-win_amd64.whl von der Verknüpfung, die Sie erwähnt haben, zu installieren. Ich habe die folgende Meldung in der Eingabeaufforderung: Anforderung bereits zufrieden: lxml == 4.0.0 aus der Datei */lxml-4.0.0-cp35-cp35m-win_amd64.whl in c: * \ python \ python35 \ lib \ site-packages. Wenn ich das Python-Skript ausführe, erhalte ich den folgenden Fehler: AttributeError: Modul 'xml.etree.ElementTree' hat kein Attribut 'XSLT' –

+0

Sie haben den richtigen Etree nicht importiert. Entfernen Sie das eingebaute Modul 'import xml.etree.ElementTree' und verwenden Sie nur lxml:' import lxml.etree as et'. – Parfait

+0

Das war der Fehler. Es funktioniert jetzt. Danke. Ich habe versucht, Ihre Lösung für eine andere Eingabedatei.Ich habe einige Änderungen in Ihrem Skript.Es gibt keine Änderungen in der Ausgabedatei überhaupt.Können Sie bitte einen Blick? Hier ist der Link von Eingabedatei und Skript: https://drive.google.com/open?id=0Bxt5bddXF4ctYUxKWDh5amRmOTA –