JavaでXML風のテキストを整形するツール

## JavaでXML風のテキストを整形するツール
1行で記載されたXML風のテキストを整形する

## やりたいことのイメージ
1行で記載されたXMLを整形する。
```
<xml><tagA><tagA-A>aaa</tagA-A><tagA-B>aaa</tagA-B></tagA><tagB-A>aaa</tagB-A><tagB-B>aaa</tagB-B><tagB><tagB-A>aaa</tagB-A><tagB-B>aaa</tagB-B></tagB>
```
これを↓のように整形する。
```
<xml>
    <tagA>
        <tagA-A>aaa</tagA-A>
        <tagA-B>aaa</tagA-B>
    </tagA>
    <tagB-A>aaa</tagB-A>
    <tagB-B>aaa</tagB-B>
    <tagB>
        <tagB-A>aaa</tagB-A>
        <tagB-B>aaa</tagB-B>
    </tagB>
```

## 前提
XMLとしてのチェックはしていない。
XMLの不備は無視してそのまま整形している。

## ソース
・batファイル(do.bat)
```
echo off
cd ./
javac IoTest.java
java IoTest
pause
```
・Javaファイル(IoTest.java)
```
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

class IoTest {

	// 外部ファイルパス
	private static final String INPUT_PATH = "./file/inputXml/";
	private static final String OUTPUT_PATH = "./file/outputXml/";

	// XML定数
	private static final String XML_START = "<";
	private static final String XML_END = ">";
	private static final String XML_SHIME = "/";
	private static final String XML_KBN_OPEN = "XML_OPEN";
	private static final String XML_KBN_CLOSE = "XML_CLOSE";
	private static final String XML_INDENT = "    ";
	private static final String XML_KAIGYO = "\r\n";

	// 改行、インデント区分
	private static final String KI_KBN_ON_PLUS = "KI_000";
	private static final String KI_KBN_ON_NON = "KI_001";
	private static final String KI_KBN_OFF_NON = "KI_002";
	private static final String KI_KBN_ON_MINUS = "KI_003";

	public static void main(String[] args) {
		try {
			// すでに出力済みのファイルを削除する。
			deleteFile();

			// INPUT_PATHに格納されているファイル分繰り返し処理をする
			File file = new File(INPUT_PATH);
			File files[] = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				execute(files[i].getName());
			}
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	public static void deleteFile() throws Exception {
		try {
			File file = new File(OUTPUT_PATH);
			File files[] = file.listFiles();

			for (File work : files) {
				Path p = Paths.get(OUTPUT_PATH + work.getName());
				Files.delete(p);
			}

		} catch (Exception e) {
			System.out.println(e);
			throw e;
		}
	}

	public static void execute(String fileName) throws Exception {
		try {
			Path path = Paths.get(INPUT_PATH + fileName);
			List<String> list = Files.readAllLines(path);
			String xmlStr = convertXml(list.get(0));
			outputXmlFile(fileName, xmlStr);
		} catch (Exception e) {
			System.out.println(e);
			throw e;
		}
	}

	public static void outputXmlFile(String fileName, String fileValue) throws Exception {
		try {
			FileWriter fw = new FileWriter(OUTPUT_PATH + fileName);
			PrintWriter pw = new PrintWriter(new BufferedWriter(fw));

			pw.println(fileValue);

			pw.close();
		} catch (Exception e) {
			System.out.println(e);
			throw e;
		}
	}

	public static String convertXml(String xmlStr) throws Exception {
		String result = "";

		try {
			// 文字列分繰り返し処理をする
			String[] workStr = xmlStr.split("");
			String[] tagInfo = {"", "", "", ""};
			int indentCount = 0;
			String kiKbn= "";
			boolean kaigyoIndentAddFlag = false;
			for (int i = 0;i < workStr.length; i++) {
				String work = workStr[i];

				// 改行、インデント設定を行う。
				if (kaigyoIndentAddFlag) {
					result = addKaigyouIndent(result, kiKbn, indentCount);
					kaigyoIndentAddFlag = false;
				}

				if (XML_START.equals(work)) {
					// 開始タグの場合、タグ情報の設定を行う。
					tagInfo = analyzeXmlTagInfo(workStr, i);
				}
				if (XML_END.equals(work)) {
					// 終了タグの場合、改行、インデント設定を行う。
					kiKbn = checkKaigyouIndent(tagInfo);
					indentCount = checkIndentCount(kiKbn, indentCount);
					kaigyoIndentAddFlag = true;
				}

				result = result + work;
			}
		} catch (Exception e) {
			System.out.println(e);
			throw e;
		}

		return result;
	}

	public static String getNextStr(String[] arrayStr, int nowIndex) throws Exception {
		String result = "";

		int size = arrayStr.length;
		int nextIndex = nowIndex + 1;

		if (size > nextIndex) {
			result = arrayStr[nextIndex];
		}

		return result;
	}

	public static String[] analyzeXmlTagInfo(String[] arrayStr, int nowIndex) throws Exception {
		String[] result = {"", "", "", ""};
		String nowXmlTagInfo = "";
		String nowXmlTagKbn = XML_KBN_OPEN;
		String nextXmlTagInfo = "";
		String nextXmlTagKbn = XML_KBN_OPEN;

		int nextTagIndex = 0;

		// 現在タグの情報を設定する。
		for (int i = nowIndex; i < arrayStr.length; i++) {
			String work = arrayStr[i];

			if (XML_START.equals(work)) {
				// 開始タグはスキップする。
				continue;
			}
			if (XML_SHIME.equals(work)) {
				// "/"の場合はタグ区分を変更する。
				nowXmlTagKbn = XML_KBN_CLOSE;
				continue;
			}
			if (XML_END.equals(work)) {
				// 終了タグは次回タグのインデックスを設定して終了する。
				nextTagIndex = i + 1;
				break;
			}

			nowXmlTagInfo = nowXmlTagInfo + work;
		}

		// 次回タグの情報を設定する。
		boolean addFlag = false;
		for (int i = nextTagIndex; i < arrayStr.length; i++) {
			String work = arrayStr[i];

			if (XML_START.equals(work)) {
				// 開始タグを検知してからタグ情報を設定する。
				addFlag = true;
				continue;
			}
			if (XML_SHIME.equals(work)) {
				// "/"の場合はタグ区分を変更する。
				nextXmlTagKbn = XML_KBN_CLOSE;
				continue;
			}
			if (XML_END.equals(work)) {
				// 終了タグは終了する。
				break;
			}

			if (addFlag) {
				nextXmlTagInfo = nextXmlTagInfo + work;
			}
		}

		result[0] = nowXmlTagInfo;
		result[1] = nowXmlTagKbn;
		result[2] = nextXmlTagInfo;
		result[3] = nextXmlTagKbn;

		return result;
	}

	public static String checkKaigyouIndent(String[] tagInfo) throws Exception {
		String result = "";

		String nowXmlTagInfo = tagInfo[0];
		String nowXmlTagKbn = tagInfo[1];
		String nextXmlTagInfo = tagInfo[2];
		String nextXmlTagKbn = tagInfo[3];

		if (XML_KBN_OPEN.equals(nextXmlTagKbn)) {
			if (XML_KBN_OPEN.equals(nowXmlTagKbn)) {
				// 改行：する、インデント：増
				result = KI_KBN_ON_PLUS;
			} else {
				// 改行：する、インデント：無
				result = KI_KBN_ON_NON;
			}
		} else {
			if (XML_KBN_OPEN.equals(nowXmlTagKbn)) {
				// 改行：しない、インデント：無
				result = KI_KBN_OFF_NON;
			} else {
				// 改行：する、インデント：減
				result = KI_KBN_ON_MINUS;
			}
		}
		
		return result;
	}

	public static int checkIndentCount(String kiKbn, int nowIndentCount) throws Exception {
		int result = nowIndentCount;

		if (KI_KBN_ON_PLUS.equals(kiKbn)) {
			// 設定するインデントを増やす
			result++;
		} else if (KI_KBN_ON_MINUS.equals(kiKbn)) {
			// 設定するインデントを減らす
			result--;
		}

		return result;
	}

	public static String addKaigyouIndent(String nowStr, String kiKbn, int indentCount) throws Exception {
		String addStr = "";

		if (KI_KBN_OFF_NON.equals(kiKbn)) {
			// 改行しない場合はそのまま返却
			return nowStr;
		}

		// 改行設定
		addStr = XML_KAIGYO;

		// インデント設定
		for (int i = 0; i < indentCount; i++) {
			addStr = addStr + XML_INDENT;
		}

		return nowStr + addStr;
	}
}
```

## 使い方
任意のディレクトリに上記のバッチファイルとJavaファイルを格納し、
以下の構成のディレクトリを作成する。
```
file
├─inputXml
└─outputXml
```
- inputXml
変換したいファイルを格納する。
- outputXml
バッチを実行すると変換されたファイルが作成される。