2011-08-09 11 views
5

Tôi có tệp xml lớn (1 Gig). Tôi muốn di chuyển một số phần tử (mục nhập) vào một tệp khác có cùng tiêu đề và thông số kỹ thuật.Làm thế nào để nói lxml.etree.tostring (phần tử) không viết các không gian tên trong python?

Hãy nói rằng các tập tin ban đầu có chứa cụm từ này với thẻ <to_move>:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE some SYSTEM "some.dtd"> 
<some> 
... 
<to_move date="somedate"> 
    <child>some text</child> 
    ... 
... 
</to_move> 
... 
</some> 

tôi sử dụng lxml.etree.iterparse để lặp qua các tập tin. Hoạt động tốt. Khi tôi tìm thấy những phần tử với thẻ <to_move>, hãy giả sử nó được lưu trữ trong biến element tôi làm

new_file.write(etree.tostring(element)) 

Nhưng kết quả này trong

<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE some SYSTEM "some.dtd"> 
<some> 
... 
<to_move xmlns:="some" date="somedate"> # <---- Here is the problem. I don't want the namespace. 
    <child>some text</child> 
    ... 
... 
</to_move> 
... 
</some> 

Vì vậy, câu hỏi là: Làm thế nào để nói với etree.tostring () không viết xmlns:="some". Điều này có thể không? Tôi đã đấu tranh với tài liệu api-lxml.etree, nhưng tôi không thể tìm thấy câu trả lời thỏa mãn.

Đây là những gì tôi tìm thấy cho etree.trostring:

tostring(element_or_tree, encoding=None, method="xml", 
xml_declaration=None, pretty_print=False, with_tail=True, 
standalone=None, doctype=None, exclusive=False, with_comments=True) 

Serialize một yếu tố để một đại diện chuỗi được mã hóa của cây XML của nó.

Với tôi, mọi thông số của tostring() dường như không hữu ích. Bất kỳ đề nghị hoặc sửa chữa?

Trả lời

5

tôi thường lấy một namespace để thực hiện một bí danh cho nó như thế này:

someXML = lxml.etree.XML(someString) 
if ns is None: 
     ns = {"m": someXML.tag.split("}")[0][1:]} 
someid = someXML.xpath('.//m:ImportantThing//m:ID', namespaces=ns) 

Bạn có thể làm một cái gì đó tương tự như lấy không gian tên để tạo ra một regex sẽ làm sạch nó sau khi sử dụng tostring.

Hoặc bạn có thể xóa chuỗi đầu vào. Tìm không gian đầu tiên, kiểm tra nếu nó được theo sau bởi xmlns, nếu có, xóa toàn bộ bit xmlns lên đến không gian tiếp theo, nếu không xóa không gian. Lặp lại cho đến khi không có thêm dấu cách hoặc khai báo xmlns. Nhưng đừng đi qua > đầu tiên.

2

Có một cách để remove namespaces with XSLT:

import io 
import lxml.etree as ET 


def remove_namespaces(doc): 
    # http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl 
    xslt='''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="no"/> 

    <xsl:template match="/|comment()|processing-instruction()"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*"> 
     <xsl:element name="{local-name()}"> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@*"> 
     <xsl:attribute name="{local-name()}"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 
    </xsl:stylesheet> 
    ''' 

    xslt_doc = ET.parse(io.BytesIO(xslt)) 
    transform = ET.XSLT(xslt_doc) 
    doc = transform(doc) 
    return doc 

doc = ET.parse('data.xml') 
doc = remove_namespaces(doc) 
print(ET.tostring(doc)) 

mang

<some> 

<to_move date="somedate"> 
    <child>some text</child> 
</to_move> 

</some> 
+0

Tôi hiểu, ý tưởng tuyệt vời * đằng sau không gian tên. :-) Nhưng trong trường hợp đặc biệt này của tôi không có lợi nhuận trong nó cả. Điều đó không có nghĩa là tôi sẽ luôn bỏ qua chúng. :-) Cảm ơn! – Aufwind

3

Điều này có ý nghĩa hơn đối với câu trả lời bằng 'unutbu', trong đó đề xuất xóa không gian tên được mong muốn mà không đưa ra ví dụ. đây có thể là những gì bạn đang tìm kiếm ...

from lxml import objectify 
objectify.deannotate(root, cleanup_namespaces=True) 
+0

Thao tác này sẽ không xóa bất kỳ không gian tên nào. Từ các tài liệu: "đệ quy de-chú thích các yếu tố của một cây XML bằng cách loại bỏ 'py: pytype' và/hoặc 'xsi: type' thuộc tính và/hoặc 'xsi: nil' thuộc tính." –

+1

Điều này gần như làm việc cho tôi, tôi vẫn có một thuộc tính 'xmlns' trong chuỗi kết quả, có cách nào để loại bỏ điều đó quá mà không sử dụng regexp không? – Dettorer

+0

Tính năng này hoạt động.Ngoài ra, tạo các phần tử với 'objectify' và tham số' annotate = False' cũng hoạt động: ví dụ: 'myE = objectify.ElementMaker (chú thích = False)' và sau đó 'x = myE.rootElem()'; bạn có thể tuần tự hóa nó bằng cách sử dụng 'etree.tostring (x, method = 'xml')' và lấy lại chỉ '' – miha