Pythonを使ったXMLの操作について解説します。
JavaとかでXMLをよく使うのがTomcatサーバの設定とかで利用するのですが、PythonでもXMLの操作ができます。
操作できるライブラリについて、この記事では紹介します。
他にもPythonでいろいろなファイルの読み書きを解説しています。
ご興味があれば、下記の記事もご覧ください。
-
Pythonでいろんな種類のファイルを操作方法を解説
Pythonを使って、テキストやJSON、YAMLといったさまざまなファイルの読み書きに関してピックアップしてみました。 調べてみてわかったことは、ほとんどのモジュールが書き込みと読み込みで同じような書き方になっていました。 そのため、数種 ...続きを見る
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とは、Document Object Modelの略でHTMLやXMLを操作するためのAPIです。
そのため文章をノードとオブジェクトで表現します。
DOMの特徴としては、ツリー構造(階層構造)でそれぞれがノードと呼ばれる。
PythonでXMLを操作できるライブラリについて
PythonでXMLを扱うために、Parseといわれる解析ライブラリがあります。
1つはPythonの標準ライブラリにある「minidom」があります。
他にも、xmltodictやdefusedxmlがあります。
ライブラリ
- minidom
- xmltodict
- defusedxml
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の使い方
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のインストール
インストール方法は、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を使って、テキストやJSON、YAMLといったさまざまなファイルの読み書きに関してピックアップしてみました。 調べてみてわかったことは、ほとんどのモジュールが書き込みと読み込みで同じような書き方になっていました。 そのため、数種 ...続きを見る
今後の人生を豊かにする為にキャリアアップのステップとして、自分への投資をしてみませんか?