python3 xml模塊


一.簡介

xml是實現不通語言或程序之間進行數據交換的協議,可擴展標記語言,標准通用標記語言的子集。是一種用於標記電子文件使其具有結構性的標記語言。xml格式如下,是通過<>節點來區別數據結構的。

XML文件示例:

<?xml version="1.0"?>
<data>  # data 是根節點 <>開頭<>結尾就表示為一個節點
    <country name="Liechtenstein">    # country節點,name是節點的屬性,屬性可以有多個,屬性值必須用引號
        <rank updated="yes">2</rank>  # rank節點,updated是節點的屬性,2表示文本內容
        <year>2023</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2026</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2026</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>

二.XML文件處理

XML文件解析的兩種方式:

  1. 解析字符串方式
  2. 解析文件方式
a.解析字符串方式
# 加載模塊,設置一個別名
from xml.etree import ElementTree as ET
 
# 打開文件,讀取XML內容,print(str_xml)則獲得整個xml文件中的內容,str_xml是個字符串
str_xml = open('xo.xml', 'r').read()
 
 
# 將字符串解析成xml特殊對象,root代指xml文件的根節點,print(root)將獲取根節點的內存地址,print(root.tag)可以獲取根節點的名稱
root = ET.XML(str_xml)
 
b.解析文件方式
from xml.etree import ElementTree as ET
 
# 直接解析xml文件
tree = ET.parse("xo.xml")
 
# 獲取xml文件的根節點
root = tree.getroot()

2.XML文件操作

  XML格式類型是節點嵌套節點,對於每一個節點均有以下功能,以便對當前節點進行操

class Element:
    """An XML element.
 
    This class is the reference implementation of the Element interface.
 
    An element's length is its number of subelements.  That means if you
    want to check if an element is truly empty, you should check BOTH
    its length AND its text attribute.
 
    The element tag, attribute names, and attribute values can be either
    bytes or strings.
 
    *tag* is the element name.  *attrib* is an optional dictionary containing
    element attributes. *extra* are additional element attributes given as
    keyword arguments.
 
    Example form:
        <tag attrib>text<child/>...</tag>tail
 
    """
 
    當前節點的標簽名
    tag = None
    """The element's name."""
 
    當前節點的屬性
 
    attrib = None
    """Dictionary of the element's attributes."""
 
    當前節點的內容
    text = None
    """
    Text before first subelement. This is either a string or the value None.
    Note that if there is no text, this attribute may be either
    None or the empty string, depending on the parser.
 
    """
 
    tail = None
    """
    Text after this element's end tag, but before the next sibling element's
    start tag.  This is either a string or the value None.  Note that if there
    was no text, this attribute may be either None or an empty string,
    depending on the parser.
 
    """
 
    def __init__(self, tag, attrib={}, **extra):
        if not isinstance(attrib, dict):
            raise TypeError("attrib must be dict, not %s" % (
                attrib.__class__.__name__,))
        attrib = attrib.copy()
        attrib.update(extra)
        self.tag = tag
        self.attrib = attrib
        self._children = []
 
    def __repr__(self):
        return "<%s %r at %#x>" % (self.__class__.__name__, self.tag, id(self))
 
    def makeelement(self, tag, attrib):
        創建一個新節點
        """Create a new element with the same type.
 
        *tag* is a string containing the element name.
        *attrib* is a dictionary containing the element attributes.
 
        Do not call this method, use the SubElement factory function instead.
 
        """
        return self.__class__(tag, attrib)
 
    def copy(self):
        """Return copy of current element.
 
        This creates a shallow copy. Subelements will be shared with the
        original tree.
 
        """
        elem = self.makeelement(self.tag, self.attrib)
        elem.text = self.text
        elem.tail = self.tail
        elem[:] = self
        return elem
 
    def __len__(self):
        return len(self._children)
 
    def __bool__(self):
        warnings.warn(
            "The behavior of this method will change in future versions.  "
            "Use specific 'len(elem)' or 'elem is not None' test instead.",
            FutureWarning, stacklevel=2
            )
        return len(self._children) != 0 # emulate old behaviour, for now
 
    def __getitem__(self, index):
        return self._children[index]
 
    def __setitem__(self, index, element):
        # if isinstance(index, slice):
        #     for elt in element:
        #         assert iselement(elt)
        # else:
        #     assert iselement(element)
        self._children[index] = element
 
    def __delitem__(self, index):
        del self._children[index]
 
    def append(self, subelement):
        為當前節點追加一個子節點
        """Add *subelement* to the end of this element.
 
        The new element will appear in document order after the last existing
        subelement (or directly after the text, if it's the first subelement),
        but before the end tag for this element.
 
        """
        self._assert_is_element(subelement)
        self._children.append(subelement)
 
    def extend(self, elements):
        為當前節點擴展 n 個子節點
        """Append subelements from a sequence.
 
        *elements* is a sequence with zero or more elements.
 
        """
        for element in elements:
            self._assert_is_element(element)
        self._children.extend(elements)
 
    def insert(self, index, subelement):
        在當前節點的子節點中插入某個節點,即:為當前節點創建子節點,然后插入指定位置
        """Insert *subelement* at position *index*."""
        self._assert_is_element(subelement)
        self._children.insert(index, subelement)
 
    def _assert_is_element(self, e):
        # Need to refer to the actual Python implementation, not the
        # shadowing C implementation.
        if not isinstance(e, _Element_Py):
            raise TypeError('expected an Element, not %s' % type(e).__name__)
 
    def remove(self, subelement):
        在當前節點在子節點中刪除某個節點
        """Remove matching subelement.
 
        Unlike the find methods, this method compares elements based on
        identity, NOT ON tag value or contents.  To remove subelements by
        other means, the easiest way is to use a list comprehension to
        select what elements to keep, and then use slice assignment to update
        the parent element.
 
        ValueError is raised if a matching element could not be found.
 
        """
        # assert iselement(element)
        self._children.remove(subelement)
 
    def getchildren(self):
        獲取所有的子節點(廢棄)
        """(Deprecated) Return all subelements.
 
        Elements are returned in document order.
 
        """
        warnings.warn(
            "This method will be removed in future versions.  "
            "Use 'list(elem)' or iteration over elem instead.",
            DeprecationWarning, stacklevel=2
            )
        return self._children
 
    def find(self, path, namespaces=None):
        獲取第一個尋找到的子節點
        """Find first matching element by tag name or path.
 
        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.
 
        Return the first matching element, or None if no element was found.
 
        """
        return ElementPath.find(self, path, namespaces)
 
    def findtext(self, path, default=None, namespaces=None):
        獲取第一個尋找到的子節點的內容
        """Find text for first matching element by tag name or path.
 
        *path* is a string having either an element tag or an XPath,
        *default* is the value to return if the element was not found,
        *namespaces* is an optional mapping from namespace prefix to full name.
 
        Return text content of first matching element, or default value if
        none was found.  Note that if an element is found having no text
        content, the empty string is returned.
 
        """
        return ElementPath.findtext(self, path, default, namespaces)
 
    def findall(self, path, namespaces=None):
        獲取所有的子節點
        """Find all matching subelements by tag name or path.
 
        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.
 
        Returns list containing all matching elements in document order.
 
        """
        return ElementPath.findall(self, path, namespaces)
 
    def iterfind(self, path, namespaces=None):
        獲取所有指定的節點,並創建一個迭代器(可以被for循環)
        """Find all matching subelements by tag name or path.
 
        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.
 
        Return an iterable yielding all matching elements in document order.
 
        """
        return ElementPath.iterfind(self, path, namespaces)
 
    def clear(self):
        清空節點
        """Reset element.
 
        This function removes all subelements, clears all attributes, and sets
        the text and tail attributes to None.
 
        """
        self.attrib.clear()
        self._children = []
        self.text = self.tail = None
 
    def get(self, key, default=None):
        獲取當前節點的屬性值
        """Get element attribute.
 
        Equivalent to attrib.get, but some implementations may handle this a
        bit more efficiently.  *key* is what attribute to look for, and
        *default* is what to return if the attribute was not found.
 
        Returns a string containing the attribute value, or the default if
        attribute was not found.
 
        """
        return self.attrib.get(key, default)
 
    def set(self, key, value):
        為當前節點設置屬性值
        """Set element attribute.
 
        Equivalent to attrib[key] = value, but some implementations may handle
        this a bit more efficiently.  *key* is what attribute to set, and
        *value* is the attribute value to set it to.
 
        """
        self.attrib[key] = value
 
    def keys(self):
        獲取當前節點的所有屬性的 key
 
        """Get list of attribute names.
 
        Names are returned in an arbitrary order, just like an ordinary
        Python dict.  Equivalent to attrib.keys()
 
        """
        return self.attrib.keys()
 
    def items(self):
        獲取當前節點的所有屬性值,每個屬性都是一個鍵值對
        """Get element attributes as a sequence.
 
        The attributes are returned in arbitrary order.  Equivalent to
        attrib.items().
 
        Return a list of (name, value) tuples.
 
        """
        return self.attrib.items()
 
    def iter(self, tag=None):
        在當前節點的子孫中根據節點名稱尋找所有指定的節點,並返回一個迭代器(可以被for循環)。
        """Create tree iterator.
 
        The iterator loops over the element and all subelements in document
        order, returning all elements with a matching tag.
 
        If the tree structure is modified during iteration, new or removed
        elements may or may not be included.  To get a stable set, use the
        list() function on the iterator, and loop over the resulting list.
 
        *tag* is what tags to look for (default is to return all elements)
 
        Return an iterator containing all the matching elements.
 
        """
        if tag == "*":
            tag = None
        if tag is None or self.tag == tag:
            yield self
        for e in self._children:
            yield from e.iter(tag)
 
    # compatibility
    def getiterator(self, tag=None):
        # Change for a DeprecationWarning in 1.4
        warnings.warn(
            "This method will be removed in future versions.  "
            "Use 'elem.iter()' or 'list(elem.iter())' instead.",
            PendingDeprecationWarning, stacklevel=2
        )
        return list(self.iter(tag))
 
    def itertext(self):
        在當前節點的子孫中根據節點名稱尋找所有指定的節點的內容,並返回一個迭代器(可以被for循環)。
        """Create text iterator.
 
        The iterator loops over the element and all subelements in document
        order, returning all inner text.
 
        """
        tag = self.tag
        if not isinstance(tag, str) and tag is not None:
            return
        if self.text:
            yield self.text
        for e in self:
            yield from e.itertext()
            if e.tail:
                yield e.tail
View Code

1.遍歷XML文檔中的所有內容

from xml.etree import ElementTree as ET
############ 解析方式一 ############
# 打開文件,讀取XML內容
str_xml = open('xo.xml', 'r').read()
# 將字符串解析成xml特殊對象,root代指xml文件的根節點
root = ET.XML(str_xml) 
############ 解析方式二 ############
# 直接解析xml文件
tree = ET.parse("xo.xml")
# 獲取xml文件的根節點
root = tree.getroot()
# 頂層標簽
print(root.tag)
# 遍歷XML文檔的第二層
for child in root:
    # 第二層節點的標簽名稱和標簽屬性
    print(child.tag, child.attrib)
    # 遍歷XML文檔的第三層
    for i in child:
        # 第二層節點的標簽名稱和內容
        print(i.tag,i.text)
# 輸出
country {'name': 'Liechtenstein'}
rank 2
year 2023
gdppc 141100
neighbor None
neighbor None
country {'name': 'Singapore'}
rank 5
year 2026
gdppc 59900
neighbor None
country {'name': 'Panama'}
rank 69
year 2026
gdppc 13600
neighbor None
neighbor None
View Code

2.遍歷XML中指定的節點

from xml.etree import ElementTree as ET
############ 解析方式一 ############
# 打開文件,讀取XML內容
str_xml = open('xo.xml', 'r').read()
# 將字符串解析成xml特殊對象,root代指xml文件的根節點
root = ET.XML(str_xml)
############ 解析方式二 ############
# 直接解析xml文件
tree = ET.parse("xo.xml")
# 獲取xml文件的根節點
root = tree.getroot()
 
# 頂層標簽
print(root.tag)
# 遍歷XML中所有的year節點
for node in root.iter('year'):
    # 節點的標簽名稱和內容
    print(node.tag, node.text)
# 輸出
year 2023
year 2026
year 2026
View Code

 

3.修改節點內容

  由於修改節點時,都在內存中進行,不會影響原文件中的內容。如果想要保存修改,則會要將內存中的內容寫入文件。

(1)解析字符串方式的修改和保存

from xml.etree import ElementTree as ET
############ 解析方式一 ############
# 打開文件,讀取XML內容
str_xml = open('xo.xml', 'r').read()
 
# 將字符串解析成xml特殊對象,root代指xml文件的根節點
root = ET.XML(str_xml)
 
############ 操作 ############
# 頂層標簽
print(root.tag)
# 循環所有的year節點
for node in root.iter('year'):
    # 將year節點中的內容自增一
    new_year = int(node.text) + 1
    node.text = str(new_year)
 
    # 設置屬性
    node.set('name', 'alex')
    node.set('age', '18')
    # 刪除屬性
    del node.attrib['name']
 
 
############ 保存文件 ############
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding='utf-8')
View Code

(2)解析文件方式的修改和保存

from xml.etree import ElementTree as ET
############ 解析方式二 ############
# 直接解析xml文件
tree = ET.parse("xo.xml")
# 獲取xml文件的根節點
root = tree.getroot()
# 頂層標簽
print(root.tag)
# 循環所有的year節點
for node in root.iter('year'):
    # 將year節點中的內容自增一
    new_year = int(node.text) + 1
    node.text = str(new_year)
  
    # 設置屬性
    node.set('name', 'alex')
    node.set('age', '18')
    # 刪除屬性
    del node.attrib['name']
############ 保存文件 ############
tree.write("newnew.xml", encoding='utf-8')
View Code

 

4.刪除節點

(1)以解析字符串方式打開XML文件的刪除

from xml.etree import ElementTree as ET
############ 解析字符串方式打開 ############
# 打開文件,讀取XML內容
str_xml = open('xo.xml', 'r').read()
# 將字符串解析成xml特殊對象,root代指xml文件的根節點
root = ET.XML(str_xml)
# 頂層標簽
print(root.tag)
# 遍歷data下的所有country節點
for country in root.findall('country'):
    # 獲取每一個country節點下rank節點的內容
    rank = int(country.find('rank').text)
 
    if rank > 50:
        # 刪除指定country節點
        root.remove(country)
############ 保存文件 ############
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding='utf-8')
View Code

(2)以解析文件方式打開的刪除

from xml.etree import ElementTree as ET
############ 解析文件方式 ############
# 直接解析xml文件
tree = ET.parse("xo.xml")
# 獲取xml文件的根節點
root = tree.getroot()
# 頂層標簽
print(root.tag)
# 遍歷data下的所有country節點
for country in root.findall('country'):
    # 獲取每一個country節點下rank節點的內容
    rank = int(country.find('rank').text)
 
    if rank > 50:
        # 刪除指定country節點
        root.remove(country)
############ 保存文件 ############
tree.write("newnew.xml", encoding='utf-8')
View Code

 

5.創建XML文件

(1)創建方式一:

from xml.etree import ElementTree as ET
# 創建根節點
root = ET.Element("famliy")
# 創建節點大兒子
son1 = ET.Element('son', {'name': '兒1'})
# 創建小兒子
son2 = ET.Element('son', {"name": '兒2'})
# 在大兒子中創建兩個孫子
grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson2 = ET.Element('grandson', {'name': '兒12'})
son1.append(grandson1)
son1.append(grandson2)
# 把兒子添加到根節點中
root.append(son1)
root.append(son1)
tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
View Code

(2)創建方式二:

from xml.etree import ElementTree as ET
# 創建根節點
root = ET.Element("famliy")
# 創建大兒子
# son1 = ET.Element('son', {'name': '兒1'})
son1 = root.makeelement('son', {'name': '兒1'})
# 創建小兒子
# son2 = ET.Element('son', {"name": '兒2'})
son2 = root.makeelement('son', {"name": '兒2'})
# 在大兒子中創建兩個孫子
# grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson1 = son1.makeelement('grandson', {'name': '兒11'})
# grandson2 = ET.Element('grandson', {'name': '兒12'})
grandson2 = son1.makeelement('grandson', {'name': '兒12'})
son1.append(grandson1)
son1.append(grandson2)
# 把兒子添加到根節點中
root.append(son1)
root.append(son1)
tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
View Code

(3)創建方式三:

from xml.etree import ElementTree as ET
# 創建根節點
root = ET.Element("famliy")
# 創建節點大兒子
son1 = ET.SubElement(root, "son", attrib={'name': '兒1'})
# 創建小兒子
son2 = ET.SubElement(root, "son", attrib={"name": "兒2"})
# 在大兒子中創建一個孫子
grandson1 = ET.SubElement(son1, "age", attrib={'name': '兒11'})
grandson1.text = '孫子'
et = ET.ElementTree(root)  #生成文檔對象
et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)
View Code

 

以上創建方式的XML默認無縮減,如果要設置縮減的話,需要修改保存方式:

from xml.etree import ElementTree as ET
from xml.dom import minidom
 
def prettify(elem):
    """將節點轉換成字符串,並添加縮進。
    """
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="\t")
 
# 創建根節點
root = ET.Element("famliy")
# 創建大兒子
# son1 = ET.Element('son', {'name': '兒1'})
son1 = root.makeelement('son', {'name': '兒1'})
# 創建小兒子
# son2 = ET.Element('son', {"name": '兒2'})
son2 = root.makeelement('son', {"name": '兒2'})
# 在大兒子中創建兩個孫子
# grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson1 = son1.makeelement('grandson', {'name': '兒11'})
# grandson2 = ET.Element('grandson', {'name': '兒12'})
grandson2 = son1.makeelement('grandson', {'name': '兒12'})
son1.append(grandson1)
son1.append(grandson2)
# 把兒子添加到根節點中
root.append(son1)
root.append(son1)
raw_str = prettify(root)
f = open("xxxoo.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()

更詳細學習:http://www.runoob.com/xml/xml-tutorial.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM