Pythonでxmlのテンプレートからxmlを作成する

Pythonのxml.etree.ElementTreeのテンプレートからの読み込みサンプル

前回のライブドアブログへの投稿(Pythonでライブドアブログに記事を投稿・取得する | ikapblog)についてテンプレートを使って投稿するサンプルをメモしておく。 xmlの操作なので、可読性があまり良くない。

複雑なのを作るなら、テンプレートエンジンを使った方が早いかも。

xmlファイルのテンプレートの中身

まずはテンプレートとなるxmlファイルの中身を紹介する。

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:app="http://www.w3.org/2007/app">
    <title>ここにタイトルを埋め込む</title>
    <author><name>author_name</name></author>
    <content type="text/html">ここにコンテンツの中身</content>
    <category term="カテゴリ名" />
    <category term="カテゴリ名2" />
    <app:control>
        <app:draft>no</app:draft>
    </app:control>
</entry>

カテゴリ名は複数設定できるようだ。author_nameは前回のブログID相当。

これをファイルとして保存しておく。

テンプレートを読み込む

悪意のあるファイルをうっかり読み込んでしまってもダメージを受けないように、defusedxml · PyPIを利用する。

インストールは、pip install defusedxmlなどで。

パース自体はファイルのパスを指定するだけで済むので、関数として使うことにした。

import xml.etree.ElementTree as ET
import defusedxml.ElementTree as DET

def gen_constructed_xml_root(filepath: str) -> ET.Element:
    """指定されたxmlファイルをパースし、ルートノードを返す。"""
    tree = DET.parse(filepath)
    return tree.getroot()

基本的にはgen_constructed_xml_root()関数を呼び、ルートノードを保持していればOK。 置き換えたり埋め込んだりする箇所はルートノードからたどることが出来る。

defusedxmlを使ってパースし、xmlのルートノードであるxml.etree.ElementTree.Elementのインスタンスを受け取る。というだけ。パースして返ってくるのはxml.etree.ElementTreeの標準ライブラリのものであることは注意しておいた方がいいだろう。

埋め込む部分を探して埋め込む

xml内の特定要素を探索し、値を埋め込むための関数を定義する。

def set_title_content_in_xml(xml_root: ET.Element, title: str,
                             content: str) -> str:
    """xmlのtitleとcontentを設定する。"""
    title_elm = xml_root.find('{*}title')
    content_elm = xml_root.find('{*}content')

    title_elm.text = title
    content_elm.text = content
    return ET.tostring(xml_root, encoding='unicode', xml_declaration=True)

{*}nameは名前空間の有無に関わらずnameを選択するという意味。

発見したら、.textでコンテンツを埋め込む。埋め込みが終わったらET.tostring()unicodeのstr文字列に変換して返す。

文字通りだが、xml_declaration=Trueを指定すると<?xml version='1.0' encoding='UTF-8'?>が先頭に付加される。

str文字列に変換できればあとは好きに出来る。

まとめ

これまでの関数を使えば以下のようなことが出来る。

# ...これまでの関数は省略

if __name__ == '__main__':
    xml_root = gen_constructed_xml_root('somefile.xml')
    # どこかでタイトルを生成
    title = create_title()
    # どこかでコンテンツを生成
    content = create_content()
    xml = set_title_content_in_xml(xml_root, title, content)
    # 保存・送信するなど
    send_xml(xml)

簡単便利。

シンプルな投稿くらいならこれでサクッと行うことができる。

便利なライブラリなどがすでにありそうだが、自分でやってみるのも大事だと思って色々試してみた。 しかし試したのが結構前なので抜けている部分もありそうなのが少しもどかしい。 しっかりとメモを残しながら試していくことにしよう。

以上です。


広告

Bitly
タイトルとURLをコピーしました