2016-04-10 1 views
0

Из документа XML я хочу сохранить один узел в файле - со всеми родительскими узлами, но без каких-либо дочерних узлов. Например, для следующего XML:Сохранить (распечатать) узел xml со своими родителями, но без детей

<?xml version="1.0" encoding="UTF-8"?> 
<kml xmlns="http://earth.google.com/kml/2.1"> 
<Document id="myid"> 
    <name>ref.kml</name> 
    <Style id="normalState"> 
    <IconStyle><scale>1.0</scale><Icon><href>yt.png</href></Icon></IconStyle>  
    </Style> 
</Document> 
</kml> 

ожидается выход для <Document> узла будет выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8"?> 
<kml xmlns="http://earth.google.com/kml/2.1"> 
<Document id="myid"> 
</Document> 
</kml> 

До сих пор я только нашел решение с повторным удалением всех дочерних элементов перед сохранением. Но, как мне нужно работать с оригинальным XML после, я должен сделать копию всего документа:

#!/usr/bin/env python 

import lxml.etree as ET # have to use [lxml] because [xml] doesn't support 'xml_declaration' 
import copy 

kml_file = ET.parse("myfile.kml") 
kml_copied = copy.deepcopy(kml_file) # .copy() is not enough, need .deepcopy() 
root = kml_copied.getroot() 
my_node = root[0] 
for child in my_node: 
    my_node.remove(child) 
print ET.tostring(kml_copied, xml_declaration=True, encoding='utf-8') 

Есть ли лучший способ сделать это? по крайней мере, чтобы избежать глубокого копирования всего документа ...

ответ

0

Рассмотрите XSLT, специальный декларативный язык, предназначенный для преобразования документов XML. И модуль lxml Python имеет встроенный процессор XSLT 1.0. Кроме того XSLT (чей сценарий является хорошо сформированный XML-документ также может адекватно обрабатывать Kml необъявленные имена):

XSLT Script (сохранить как .xsl быть загружены в Python, а также переносит на другие языках)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
       xmlns:doc="http://earth.google.com/kml/2.1"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*"/> 

    <!-- Identity Transform to copy entire document --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- Empty Template to Remove Nodes --> 
    <xsl:template match="doc:Style|doc:name"/> 

</xsl:transform> 

Python Script

import lxml.etree as ET 

# LOAD XML AND XSL 
dom = ET.parse('Input.xml') 
xslt = ET.parse('XSLTScript.xsl') 

# TRANSFORM INPUT INTO DOM OBJECT 
transform = ET.XSLT(xslt) 
newdom = transform(dom) 

# OUTPUT DOM TO STRING 
tree_out = ET.tostring(newdom, 
         encoding='UTF-8', 
         pretty_print=True, 
         xml_declaration=True) 
print(tree_out.decode("utf-8")) 

# SAVE RESULTING XML 
xmlfile = open('Output.xml','wb') 
xmlfile.write(tree_out) 
xmlfile.close() 

Выход

<?xml version='1.0' encoding='UTF-8'?> 
<kml xmlns="http://earth.google.com/kml/2.1"> 
    <Document id="myid"/> 
</kml> 
+0

Хорошо, я думал, что запуск XSLT-оборудования для столь простой задачи будет немного переборщить :) Но я буду считать, спасибо за ваш ответ! –

+0

Обратите внимание, что другие XML-модификации могут обрабатываться в одном скрипте XSLT в дополнение к удалению узлов. И вы можете встроить XSLT внутри Python вместо внешнего файла. Кроме того, файл переносится на другие языки и исполняемые файлы (Java, PHP, C#, VBA, Saxon, Xalan). Конечно, масштабируемый ответ! Если это поможет, пожалуйста, подтвердите разрешение. – Parfait