pythonでxmlファイルをフォーマットして出力する

作成: 2019年05月03日

更新: 2021年03月29日

目標

DjangoでQiita風のブログを作ろう
でmarkdownで書いた記事をこのページのようにアップロードすることができた。そこでアップロードするときにこのWebサイト全体のサイトマップに記事のページを追加するようにしたい。

問題点

xmlファイルはpythonではxml.etree.ElementTree
モジュールを用いてパースして追加、削除などができる。たとえば記事投稿時に以下のようにすればいい。

sitemap.xml<?xml version="1.0" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://banatech.tk/</loc>
        <lastmod>2019-03-03T12:37:10+00:00</lastmod>
        <priority>1.00</priority>
    </url>
</urlset>
import xml.etree.ElementTree as ET
# sitemap.xmlへの追加
xmlTree = ET.parse(settings.BASE_DIR + "/path/to/sitemap.xml")
ET.register_namespace('', 'http://www.sitemaps.org/schemas/sitemap/0.9') #こうしないと勝手にns0の名前空間が作られる
root = xmlTree.getroot()
url = ET.SubElement(root, "url")
loc = ET.SubElement(url, "loc")
lastmod = ET.SubElement(url, "lastmod")
priority = ET.SubElement(url, "priority")
loc.text = "https://banatech.tk/blog/" + str(article.id)
dt = datetime.datetime.strptime(str(timezone.datetime.now()), "%Y-%m-%d %H:%M:%S.%f")
lastmod.text = dt.strftime("%Y-%m-%dT%H:%M:%S+00:00")
priority.text = "0.64"
xmlTree.write(settings.BASE_DIR + "/static/sitemap/sitemap.xml")

しかしこれではsitemap.xmlは以下のように改行もインデントもなしに追加されてしまう。

sitemap.xml<?xml version="1.0" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://banatech.tk/</loc>
        <lastmod>2019-03-03T12:37:10+00:00</lastmod>
        <priority>1.00</priority>
    </url>
    <url><loc>https://banatech.tk/blog/1</loc><lastmod>2019-03-03T12:37:10+00:00</lastmod><priority>0.64</priority></url>
</urlset>

何とかサイトマップをきれいなままにしたい。

xml.dom.mindomの使用

このページを参考にした。
Creating XML Documents - Python Module of the Week

from xml.dom import minidom
import re
import xml.etree.ElementTree as ET
#xmlフォーマット用
def prettify(elem):
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    pretty = re.sub(r"[\t ]+\n", "", reparsed.toprettyxml(indent="\t"))
    pretty = pretty.replace(">\n\n\t<",">\n\t<")
    return pretty

# sitemap.xmlへの追加
xmlTree = ET.parse(settings.BASE_DIR + "/path/to/sitemap.xml")
ET.register_namespace('', 'http://www.sitemaps.org/schemas/sitemap/0.9') #こうしないと勝手にns0の名前空間が作られる
root = xmlTree.getroot()
url = ET.SubElement(root, "url")
loc = ET.SubElement(url, "loc")
lastmod = ET.SubElement(url, "lastmod")
priority = ET.SubElement(url, "priority")
loc.text = "https://banatech.tk/blog/" + str(article.id)
dt = datetime.datetime.strptime(str(timezone.datetime.now()), "%Y-%m-%d %H:%M:%S.%f")
lastmod.text = dt.strftime("%Y-%m-%dT%H:%M:%S+00:00")
priority.text = "0.64"
with open(settings.BASE_DIR + "/path/to/sitemap.xml",mode='w') as f:
    f.write(prettify(root))

xml.dom.mindomモジュールを用いてインデントを追加後不必要なタブ、改行を正規表現で取り除いた。これでxmlにきれいなままページを追加できる。

ElementTree.find

先ほどのコードでは名前空間をつけられないようにしているがこの場合

root.find("url")

などでは見つからないので

root.find("{http://www.sitemaps.org/schemas/sitemap/0.9}url")

としなければならない