【Python】過去の過ち（XML）を書き直す

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