LoginSignup
3
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-06-24

急いでプログラムとかしてると「まあいっか」という軽いノリで過ちを犯し、あとあとになってとんでもないことになってることってありますよね。
過去に作ったゲームの設定ファイルの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で組んでいこうかなと思います。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3