【Python】ディレクトリ構造をXML形式に変換する
概要
PythonでXMLを便利に扱えるElementTreeの使い方を紹介します。
あと少し自作ツールのお披露目です。
経緯
業務で使用したIDEが、プロジェクトにソースコードを1ファイルずつしか追加できないという衝撃的な仕様だったため、設定ファイルのXMLを直接作成しようということになりました。
ElementTree(通称ET)
PythonでXMLをツリー構造として操作できるライブラリです。
PythonのチュートリアルではET
という略称が公式で使われています。
XMLの構造を保持する
ETでは、ツリー構造の一つの要素をElement
クラスを使って保持します。
Element
クラスは、下記の属性を持っています。
- tag
- XMLのタグを表す属性
- text
- 要素のデータ
- tail
- アプリケーション固有の付加的なデータ
- XMLの閉じタグの後に置かれるイメージ
- attrib
- 要素の属性
- SubElement
- 要素の子要素(
Element
型)
- 要素の子要素(
XMLのイメージでいうと、それぞれ下記の部分に該当します。
<tag attrib="attrib">
text
<SubElement>
SubText
<SubElement>
</tag>tail
XMLを構築する
ETを使って、XMLをツリー構造として構築していきます。
まずは、Element()
メソッドでルートとなる要素を生成します。
import xml.etree.ElementTree as ET
root = ET.Element('root') # rootタグを生成
データはtext
に直接代入することで追加します。
root.text = 'data'
子要素はSubElement()
で追加できます。
もしくは、Elementに直接append()
を使って追加することもできます。
SubElement()
は追加した要素を返してくれるので、要素の追加と取得を一度にできてお得です。
import xml.etree.ElementTree as ET
root = ET.Element('root') # rootタグを生成
root.text = 'data' # rootのデータとしてdataを設定
sub = ET.SubElement(root, 'sub') # rootの子要素としてsubを追加
# root.append(ET.Element('sub')) # こちらでも可能
要素の検索
ツリー構造の要素を検索するためにはElementクラスのfindall()
メソッドもしくはfind()
メソッドを利用します。
二つの違いは、findall()
は指定したタグをすべて取得しますが、find()
メソッドは最初に見つかった一つだけを取得します。
import xml.etree.ElementTree as ET
root = ET.Element('root')
sub1 = ET.SubElement(root, 'sub')
sub2 = ET.SubElement(root, 'sub')
sub3 = ET.SubElement(root, 'sub')
# findall()はリストが返ってくる
for ele in root.findall('sub'):
ele.text = 'data'
# find()では最初の一つだけ
subEle = root.find('sub')
subEle.text = 'first'
ファイル入出力
ETはファイルからXMLの構造を読み込むこともできます。
import xml.etree.ElementTree as ET
ET.parse('example.xml') # example.xmlをツリー構造として取り込む
自分で作成したツリー構造をファイルに出力するためには、文字列に変換してからファイルに出力します。
文字列に変換するためにはtostring()
メソッドを使います。
import xml.etree.ElementTree as ET
root = ET.Element('root') # rootタグを生成
root.text = 'data' # rootのデータとしてdataを設定
sub = ET.SubElement(root, 'sub') # rootの子要素としてsubを追加
# root.append(ET.Element('sub')) # こちらでも可能
fp = open('output.xml', 'w')
fp.write(ET.tostring(root, 'unicode')) # 文字列に変換してからファイル出力
作成したツール
これまでの内容を使って、ディレクトリ構造をXML形式に変換するツールを作成しました。
業務で使っているIDEの環境に合わせて作っているので、あまり汎用的なツールになってはいませんが、参考になれば幸いです。
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
import sys
import re
# Define constants
tag_group='group'
tag_name='name'
tag_file='file'
# Main function
def main():
if len(sys.argv) < 2:
print('Please input the directory path which is as root: ')
root_path = sys.stdin.readline().rstrip()
else:
root_path = sys.argv[1]
root = ET.Element('root')
print('Converting Directories to XML...')
ele_curr = root
for path, directories, files in os.walk(root_path):
group_path = re.sub('^\\' + os.path.sep, '', path.replace(root_path, ''))
if group_path != '':
# the root path has no name, so skipped.
ele_curr = find_named_element(root, group_path)
for dir in directories:
ele_curr.append(create_new_group(dir))
for file in files:
# This statement is specified for my tool.
# $PROJ_DIR$ is context root for my tool.
ele_curr.append(create_new_file(os.path.join('$PROJ_DIR$', group_path, file)))
print('Convertion Completed!')
output_file_name = os.path.join(root_path, 'result.xml')
print('Output File : %s' %(output_file_name))
output_to_file(root, output_file_name)
# Define functions
def find_named_element(ele, name):
name_list = name.split(os.path.sep)
ele_curr = ele
for target in name_list:
ele_pre = ele_curr
for group in ele_curr.findall(tag_group):
ele_name = group.find(tag_name)
if ele_name.text == target:
ele_curr = group
break
if ele_curr is ele_pre:
ele_new = create_new_group(target)
ele_curr.append(ele_new)
ele_curr = ele_new
return ele_curr
def create_new_element(name, tag):
ele = ET.Element(tag)
ele_name = ET.SubElement(ele, tag_name)
ele_name.text = name
return ele
def create_new_group(name):
return create_new_element(name, tag_group)
def create_new_file(name):
return create_new_element(name, tag_file)
def output_to_file(element, file_name):
fp = open(file_name, 'w')
fp.write(ET.tostring(element, 'unicode'))
main()
下記のディレクトリexample
をXML形式に変換してみます。
C:\EXAMPLE
│ file1.txt
│ file2.txt
│
├─SubDir1
│ file1.txt
│ file2.txt
│
└─SubDir2
└─SubDir3
file1.txt
file2.txt
c:\>Dir2XML.py .\example
<root>
<group>
<name>SubDir1</name>
<file>
<name>$PROJ_DIR$\SubDir1\file1.txt</name>
</file>
<file>
<name>$PROJ_DIR$\SubDir1\file2.txt</name>
</file>
</group>
<group>
<name>SubDir2</name>
<group>
<name>SubDir3</name>
<file>
<name>$PROJ_DIR$\SubDir2\SubDir3\file1.txt</name>
</file>
<file>
<name>$PROJ_DIR$\SubDir2\SubDir3\file2.txt</name>
</file>
</group>
</group>
<file>
<name>$PROJ_DIR$\file1.txt</name>
</file>
<file>
<name>$PROJ_DIR$\file2.txt</name>
</file>
</root>
※result.xml
は表示用に整形しています。実際は1行にすべて出力されています。
GitHubにも公開しています。
Dir2XML
Author And Source
この問題について(【Python】ディレクトリ構造をXML形式に変換する), 我々は、より多くの情報をここで見つけました https://qiita.com/HAMADA_Hiroshi/items/0b9db971f1e0c1002055著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .