Python

PythonでXMLを使ったDOMを操作!3つのライブラリの使い方を解説

2021年9月9日

Python XMLでDOM操作

Pythonを使ったXMLの操作について解説します。

JavaとかでXMLをよく使うのがTomcatサーバの設定とかで利用するのですが、PythonでもXMLの操作ができます。

操作できるライブラリについて、この記事では紹介します。

他にもPythonでいろいろなファイルの読み書きを解説しています。

ご興味があれば、下記の記事もご覧ください。

Pythonファイル操作
Pythonでいろんな種類のファイルを操作方法を解説
Pythonを使って、テキストやJSON、YAMLといったさまざまなファイルの読み書きに関してピックアップしてみました。 調べてみてわかったことは、ほとんどのモジュールが書き込みと読み込みで同じような書き方になっていました。 そのため、数種 ...

続きを見る

XMLとは

XMLとは

XMLとは、「Extensible Markup Language」の略で、日本語ですると拡張可能なマークアップ言語です。

拡張可能なマークアップ言語とは何かというと、HTMLもマークアップゲントですが、決められたタグしか使うことができません。

H1タグとかPタグやDIVタグなどです。

しかし、XMLはタグの名称をいろいろと設定することができます。

例えばPythonタグやVersionといった形で設定することができます。

実際に書くと下記のように感じです。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
  <Version>3.9.0</Version>
</Python>

DOMとは

DOMとは

DOMとは、Document Object Modelの略でHTMLやXMLを操作するためのAPIです。

そのため文章をノードとオブジェクトで表現します。

DOMの特徴としては、ツリー構造(階層構造)でそれぞれがノードと呼ばれる。

PythonでXMLを操作できるライブラリについて

PythonでXMLを操作できるライブラリについて

PythonでXMLを扱うために、Parseといわれる解析ライブラリがあります。

1つはPythonの標準ライブラリにある「minidom」があります。

他にも、xmltodictやdefusedxmlがあります。

ライブラリ

  • minidom
  • xmltodict
  • defusedxml

minidomの使い方

minidomの使い方

minidomとは、DOMを操作するための最低限の実装されたインターフェースです。

最低限ということもあり、非常に小さくなるように設計されています。

そのため、悪意あるデータに対しては安全ではありません。

minidomを利用するには、安全性には注意する必要があります

minidomのインストール

インストールについては、Pythonの標準ライブラリのため、不要になります。

XMLデータ文字列として取得

XMLのデータを文字列として返す関数が、toxml関数になります。

今回、読み込んで文字列化するデータは下記になります。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
    <Version>Python3.9.0</Version>
</Python>

このXMLデータを下記のコードを使って、XMLから文字列として値を返します。

from xml.dom.minidom import parse

doc = parse('./sample.xml').toxml()
print(doc)
print(type(doc))

下記は、printで出力した結果になります。

<?xml version="1.0" ?><Python>
    <Version>Python3.9.0</Version>
</Python>
<class 'str'>

結果としてPython開始タグの改行文字が崩れたのと、typeで返した値はstrと返ってきています。

XMLファイルの作成

minidomを使って、DOMの書き込み操作を行います。

下記が書き込みを行なっているコードになります。

import xml
from xml.dom import minidom

with open('./write_sample.xml', 'w') as f:
    impl = xml.dom.minidom.getDOMImplementation()
    doc = impl.createDocument(None, '会社', None)
    root = doc.documentElement
    el = doc.createElement('会社名')
    txt = doc.createTextNode('サンプル会社')
    attr = doc.createAttribute('since')
    attr.value = '2021-09-09'
    el.setAttributeNode(attr)
    el.appendChild(txt)
    root.appendChild(el)
    doc.writexml(writer=f, encoding='UTF-8', newl='\n', addindent='\t')

getDOMImplementationでXMLを生成する準備を行い、createDocumentでXMLのオブジェクトを作成しています。

作成したオブジェクトを元に、documentElementでXMLのルートを取得します。

createElementでエレメントを作成します。

createTextNodeでテキストを生成しており、createElementで作成した要素に先ほど作成したテキストを入れます。

appendChildが要素の中に入れる処理になります。

属性の処理については、createAttributeを使います。

作成した属性にvalueを使って値を入れます。

writexmlでXMLファイルの作成しています。

作成したXMLファイルの中身は下記になります。

<?xml version="1.0" encoding="UTF-8"?>
<会社>
	<会社名 since="2021-09-09">サンプル会社</会社名>
</会社>

XMLの書き込みでは、下記の関数を覚えておけば問題ないです。

XMLの書き込み関数

  • createDocument
  • createElement
  • createTextNode
  • createAttribute
  • setAttributeNode
  • appendChild

xmltodictの使い方

xmltodictの使い方

XMLデータを辞書型として返すことができます。

2019年で開発が止まっていますが、紹介したいと思います。

xmltodictのインストール

xmltodictをインストールするには、pipでインストールします。

$ pip install xmltodict

実際に辞書型として取得してみる

実際に辞書型として取得してみます。

XMLデータは、minidomでも利用した下記のデータを使います。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
    <Version>Python3.9.0</Version>
</Python>

このデータを元に、Versionの値を取得してみます。

import xmltodict as xmltodict

with open('./sample.xml') as f:
    doc = xmltodict.parse(f.read())
    print(doc['Python']['Version']) # 結果 Python3.9.0

ファイルを開くopen関数を使わずに、minidomの文字列としてparseすることもできます。

from xml.dom.minidom import parse
import xmltodict as xmltodict

obj = parse('./sample.xml')
doc2 = xmltodict.parse(obj.toxml())
print(doc2['Python']['Version']) # 結果 Python3.9.0

属性の取得

属性(attribute)として取得してみます。

単純にタグだけの操作では、実務的に微妙なので実際に属性も取得してみます。

XMLデータは下記になります。

追加としてdescriptionの要素を追加して、属性としてdateを追加しています。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
    <Version>Python3.9.0</Version>
    <description date="2021-09-09">コメントをしてみる</description>
</Python>

実際に属性のdateを取得してみます。

取得する方法は、@マークを使います。

下記が取得するコードになります。

from xml.dom.minidom import parse
import xmltodict as xmltodict

obj = parse('./sample.xml')
doc2 = xmltodict.parse(obj.toxml())
print(doc2['Python']['description']['@date']) # 結果 2021-09-09

defusedxmlの使い方

defusedxmlの使い方

defusedxmlは、誤ったデータや悪意のあるデータなどの対策から利用します。

セキュリティや脆弱性の面から、defusedxmlを利用するようにしましょう。

概要とかどういったものなのか確認したかったのですが、公式のほとんどがセキュリティについての内容でした。

defusedxmlのインストール

インストール方法は、pipコマンドを利用します。

$ pip install defusedxml

ルートエレメントを取得

実際にdefusedxmlを使ってDOMの操作をしてみます。

読み込むファイルは、下記になります。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
    <Version>Python3.9.0</Version>
</Python>

下記はXMLのルートを取得しています。

from defusedxml import ElementTree

root = ElementTree.parse('./sample.xml').getroot()
print(root.tag) # 結果は Pythonが表示される

ElementTreeのparse関数を使って、XMLファイルを読み込みます。

読み込んだXMLファイルをオブジェクトからgetroot関数を使うことでXMLのデータ構造の<Python>のデータを取得しています。

tagを付けることで文字列としてタグ名を取得しています。

エレメントのデータを取得

Versionの中身を取得してみます。

XMLファイルは先ほどのsample.xmlを使います。

from defusedxml import ElementTree

root = ElementTree.parse('./sample.xml').getroot()
print(root.find('Version').text) # 結果は Python3.9.0が表示される

Pythonタグからfind関数を利用して、Versionタグを検索しています。

取得した結果を、textを使って中のデータを表示しています。

FindAllで子エレメントを取得

FindAll関数を使ってみます。

FindAll関数は、複数の子や孫のエレメントがあった場合に、いっきに取得することができます。

読み込むXMLファイルを修正します。

Bookの中に、Sectionが2つある構造に変更しています。

<?xml version="1.0" encoding="UTF-8" ?>
<Python>
    <Version>Python3.9.0</Version>
    <Book>
        <Section>基本</Section>
        <Section>モジュールの読み方</Section>
    </Book>
</Python>

実際にSectionだけを取得してみます。

from defusedxml import ElementTree

root = ElementTree.parse('./sample.xml').getroot()

list = root.findall('.//Section')
for data in list:
    print(data.text)

findallで下記のように指定すると取得することはできません。

list = root.findall('Section')

孫のエレメントを取得するには、「.//」で取得するようにしてください。

まとめ

Pythonを使って、XMLを操作しました。

XMLを操作するには、minidom、xmltodic、defusedxmlがあります。

基本的には、セキュリティのことを考えdefusedxmlを使うようにしましょう。

XML自体セキュリティを意識しないといけないデータ扱いなので、利用する際には十分に注意して取り扱ってください。

他にもPythonでいろいろなファイルの読み書きを解説しています。

ご興味があれば、下記の記事もご覧ください。

Pythonファイル操作
Pythonでいろんな種類のファイルを操作方法を解説
Pythonを使って、テキストやJSON、YAMLといったさまざまなファイルの読み書きに関してピックアップしてみました。 調べてみてわかったことは、ほとんどのモジュールが書き込みと読み込みで同じような書き方になっていました。 そのため、数種 ...

続きを見る

Udemyへ

今後の人生を豊かにする為にキャリアアップのステップとして、自分への投資をしてみませんか?

-Python
-,