Help us understand the problem. What is going on with this article?

【Python】過去の過ち(XML)を書き直す

More than 3 years have passed since last update.

急いでプログラムとかしてると「まあいっか」という軽いノリで過ちを犯し、あとあとになってとんでもないことになってることってありますよね。
過去に作ったゲームの設定ファイルのXMLがひどい状況だったのでPython使って直してみました。
(各タグの意味は説明なしでーす)

<?xml version="1.0" ?>
<charadata>
    <item>
        <id>0</id>
        <textureId>0</textureId>
        <finishIndex>2</finishIndex>
        <soundEffect>0</soundEffect>
        <motion>
            <frameCount>8</frameCount>
            <imageIndex>0</imageIndex>
        </motion>
        <motion>
            <frameCount>8</frameCount>
            <imageIndex>1</imageIndex>
        </motion>
        <motion>
            <frameCount>18</frameCount>
            <imageIndex>2</imageIndex>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
    </item>
    <item>
        <id>1</id>
        <textureId>2</textureId>
        <finishIndex>0</finishIndex>
        <soundEffect>0</soundEffect>
        <motion>
            <frameCount>4</frameCount>
            <imageIndex>0</imageIndex>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
    </item>
    <item>
        <id>2</id>
        <textureId>2</textureId>
        <finishIndex>1</finishIndex>
        <soundEffect>0</soundEffect>
        <motion>
            <frameCount>4</frameCount>
            <imageIndex>1</imageIndex>
        </motion>
        <motion>
            <frameCount>4</frameCount>
            <imageIndex>0</imageIndex>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
        <motion>
            <frameCount/>
            <imageIndex/>
        </motion>
    </item>
</charadata>

とすべきだったのを

<?xml version="1.0" ?>
<charadata>
    <item>
    <id>0</id>
    <finishIndex>2</finishIndex> 
    <soundEffect>0</soundEffect>
    <textureId>0</textureId>
    <frameCount_00>8</frameCount_00>
    <frameCount_01>8</frameCount_01>
    <frameCount_02>18</frameCount_02>
    <frameCount_03></frameCount_03>
    <imageIndex_00>0</imageIndex_00>
    <imageIndex_01>1</imageIndex_01>
    <imageIndex_02>2</imageIndex_02>
    <imageIndex_03></imageIndex_03>
    </item>

    <item>
    <id>1</id>
    <textureId>2</textureId>
    <finishIndex>0</finishIndex>
    <soundEffect>0</soundEffect>
    <frameCount_00>4</frameCount_00>
    <frameCount_01></frameCount_01>
    <frameCount_02></frameCount_02>
    <frameCount_03></frameCount_03>
    <imageIndex_00>0</imageIndex_00>
    <imageIndex_01></imageIndex_01>
    <imageIndex_02></imageIndex_02>
    <imageIndex_03></imageIndex_03>
    </item>

    <item>
    <id>2</id>
    <textureId>2</textureId>
    <finishIndex>1</finishIndex>
    <soundEffect>0</soundEffect>
    <frameCount_00>4</frameCount_00>
    <frameCount_01>4</frameCount_01>
    <frameCount_02></frameCount_02>
    <frameCount_03></frameCount_03>
    <imageIndex_00>1</imageIndex_00>
    <imageIndex_01>0</imageIndex_01>
    <imageIndex_02></imageIndex_02>
    <imageIndex_03></imageIndex_03>
    </item>
</charadata>

とやらかしてました。
リスト状にすべきところを個別のタグにして管理しちゃってます。
ひどい手抜きです。

この(魂が)間違ってるXMLを再利用する機会ができたのですが、

・手打ちで直すにはしんどい量

・プログラムを使って直した方が正確

…ということで以下のように、軽ーくプログラムを組んでみました。
(なんともまあ、教科書的なプログラムの用途)

exchange_xml.py
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom

# 入力元
src_path = "./aaaa.xml"
tree = ET.parse(src_path)
src_root = tree.getroot()
print("src_root:"+src_root.tag)

# 出力先
dest_path = "./aaaa02.xml"
dest_root = ET.Element(src_root.tag)
print("dest_root:"+dest_root.tag)

# XML内要素取得&書き換え
for item in src_root.findall("item"):
    # 要素取得、None(=NULLみたいなもん)ならば空文字を入れておく
    id=""
    textureId=""
    finishIndex=""
    soundEffect=""

    frameCount_00=""
    frameCount_01=""
    frameCount_02=""
    frameCount_03=""
    imageIndex_00=""
    imageIndex_01=""
    imageIndex_02=""
    imageIndex_03=""

    if item.find("id").text is not None:
        id = item.find("id").text

    if item.find("textureId").text is not None:
        textureId = item.find("textureId").text

    if item.find("finishIndex").text is not None:
        finishIndex = item.find("finishIndex").text

    if item.find("soundEffect").text is not None:
        soundEffect = item.find("soundEffect").text

    if item.find("frameCount_00").text is not None:
        frameCount_00 = item.find("frameCount_00").text

    if item.find("frameCount_01").text is not None:
        frameCount_01 = item.find("frameCount_01").text

    if item.find("frameCount_02").text is not None:
        frameCount_02 = item.find("frameCount_02").text

    if item.find("frameCount_03").text is not None:
        frameCount_03 = item.find("frameCount_03").text

    if item.find("imageIndex_00").text is not None:
        imageIndex_00 = item.find("imageIndex_00").text

    if item.find("imageIndex_01").text is not None:
        imageIndex_01 = item.find("imageIndex_01").text

    if item.find("imageIndex_02").text is not None:
        imageIndex_02 = item.find("imageIndex_02").text

    if item.find("imageIndex_03").text is not None:
        imageIndex_03 = item.find("imageIndex_03").text

    # 出力情報セット
    dest_item = ET.SubElement(dest_root, "item")

    dest_id = ET.SubElement(dest_item, "id")
    dest_id.text = id

    dest_textureId = ET.SubElement(dest_item, "textureId")
    dest_textureId.text = textureId

    dest_finishIndex = ET.SubElement(dest_item, "finishIndex")
    dest_finishIndex.text = finishIndex

    dest_soundEffect = ET.SubElement(dest_item, "soundEffect")
    dest_soundEffect.text = soundEffect

    # リスト情報をセットする
    # 0番目
    motion00 = ET.SubElement(dest_item, "motion")
    motion00_frameCount = ET.SubElement(motion00, "frameCount")
    motion00_frameCount.text = frameCount_00

    motion00_imageIndex = ET.SubElement(motion00, "imageIndex")
    motion00_imageIndex.text = imageIndex_00

    # 1番目
    motion01 = ET.SubElement(dest_item, "motion")
    motion01_frameCount = ET.SubElement(motion01, "frameCount")
    motion01_frameCount.text = frameCount_01

    motion01_imageIndex = ET.SubElement(motion01, "imageIndex")
    motion01_imageIndex.text = imageIndex_01

    # 2番目
    motion02 = ET.SubElement(dest_item, "motion")
    motion02_frameCount = ET.SubElement(motion02, "frameCount")
    motion02_frameCount.text = frameCount_02

    motion02_imageIndex = ET.SubElement(motion02, "imageIndex")
    motion02_imageIndex.text = imageIndex_02

    # 3番目
    motion03 = ET.SubElement(dest_item, "motion")
    motion03_frameCount = ET.SubElement(motion03, "frameCount")
    motion03_frameCount.text = frameCount_03

    motion03_imageIndex = ET.SubElement(motion03, "imageIndex")
    motion03_imageIndex.text = imageIndex_03

# 組みなおしたXMLを新しく出力
string = ET.tostring(dest_root, 'utf-8')
pretty_string = minidom.parseString(string).toprettyxml(indent='    ')

with open(dest_path, 'w') as f:
    f.write(pretty_string)

これでOK。
Pythonのバージョンは、2.7でも3.5でもいけました。
各要素名とかは定数にしたり、正規表現を使ったほうがよかったのでしょうが、それほど大きいプログラムでもないし、人様に紹介するならこんなもんでもいいかなと。
ElementTreeやminidomに関しては基礎的なお話は検索するとバンバン出てくるのでそちらを参考にしてください。
今回は「XMLを読み込んで解析」と「XMLの情報を書き直してファイル出力」しただけです。

実はPythonはまだまだ初心者で、たまたま今回プログラムでやるべきことができてしまったので「じゃあPythonでやっちまおう!なんか流行ってるっぽいし!プログラムする目的が同じならば誰が組んでも同じコードになるってのが気になるし!」ってノリで始めたのですが……いやー、いいっすね、Python。
何がいいって一番は対話形式でプログラムを試せることですね。
これが初心者にやさしいんです(いやマジで)。
プログラムを1行ずつ打つことで、文法のチェックやエラーメッセージの確認もできる。
あとは(本当はよくないんだろうけど)実際にコードを打ちながらプログラムの流れを考えることでもできる。
今後もちょっとした処理が必要になれば、Pythonで組んでいこうかなと思います。

bcosizm
長年、広く浅くやってきた結果、自分はどんなエンジニアといっていいのかと悩む日々。主な使用言語はC言語、C++、Java、ActionScript3、JavaScript、PHP、SQL。 プライベートでAndroidアプリ配布したり、プログラムだけでなくいろいろゴチャゴチャやってます。大昔にWindowsで「RoughMetal」「NAMAKO02」ってフリーゲーム配布してました。
http://www012.upp.so-net.ne.jp/B-cos/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away