xmlファイルの一部だけを編集できるhtaアプリ

イメージ 1

xmlで書かれた設定ファイルの特定のattributeやinnerTextだけを変えたいとき、
その変えたい部分だけを表示・編集できるツールをhtaで作成してみました。

xmlNodeEditor.hta内のxpathesは、xmlファイルの編集対象箇所を表しています。
各行の1つめは編集対象タグのXPath、2つめは編集対象属性名(nullのときは子要素全体が編集対象)です。

下記内容をコピペして拡張子htaで保存して実行すると↑の画面が表示されます。
記事の下側にあるtest.xmlを試しに編集してみて下さい。
* xmlNodeEditor.htaソース
<html>
<head>
<title>xml文書内属性エディタ</title>
<script>
/// 設定
var xpathes = [
// 編集対象タグのXPath attribute名(nullの場合子要素が編集対象)
["/xml/tag", null],
["/xml/text[@attname='hoge']", "attname"],
["/xml/textbox[@id='txt']", null],
["//target", null]
];
</script>
<!--

/// View

-->
<style>
table {
border-collapse: collapse;
};
th,td{
border: 1px solid black;
}
th {
background-color: Silver;
};
</style>
</head>
<body>
対象ファイル:<input id="target_file" value="test.xml" />
<button id="load">読み込み</button>
<button id="save">保存</button>
<div id="contents" />
</body>
<script>

/// Control

// docの内容を表示する。
function model2view() {
var tbl = document.getElementById('contents');
var html = "<table><thead><th>XPath</th><th>タイプ</th><th>名</th><th>値</th></thead><tbody>";
for (var j = 0; j < doc.items.length; ++j) {
var item = doc.items[j];
html += "<tr><td>" + item.xpath + "</td>";
var val = "", type, fc, dom = item.dom;
switch (item.type) {
case 0:
type = "attribute";
val = dom.value;
break;
default:
type = "element";
var nodes = dom.childNodes;
for (var i = 0; i < nodes.length; ++i) val += nodes.item(i).xml;
break;
}
html +=
"<td>" + type + "</td>" +
"<td>" + dom.nodeName + "</td>" +
"<td><input type='text' value='" + val + "'/></td></tr>";
}
html += "</tbody></table>";
tbl["innerHTML"]=html;

}

// input要素配列を取得する。
function query_tableinputtags() {
var ret = ;
var stack =
;
stack.push(document.getElementById('contents').firstChild);
while (stack.length > 0) {
var cur = stack.pop();
if (cur.tagName != null && cur.tagName.toLowerCase() == 'input') ret.push(cur);
while (cur != null) {
var fc = cur.firstChild;
if (fc != null) stack.push(fc);
cur = cur.nextSibling;
}
}
ret.reverse();
return ret;
}

// 表示内容を読み込みdocに書き込む
function view2model() {
var nodes = query_tableinputtags();
var j = 0, len = nodes.length;
for (j = 0; j < len; ++j) {
var item = doc.items[j];
switch (item.type) {
case 0:
item.dom.value = nodes[j].value;
break;
default:
// テキスト内のxmlタグが不正の場合は、上書きしない。
if (partdom.loadXML('<xml>'+nodes[j].value+'</xml>')){
item.dom.text = "";
while(partdom.firstChild.firstChild != null) {
item.dom.appendChild(partdom.firstChild.firstChild);
}
}
break;
}
}
}

var ctr_tf = document.getElementById('target_file');
// 読み込みクリック時の処理
document.getElementById('load').onclick = function () {
read_xml(ctr_tf.value);
model2view();
}
// 保存クリック時の処理
document.getElementById('save').onclick = function () {
view2model();
var fn = ctr_tf.value;
write_xml(fn);
read_xml(fn);
model2view();
}

/// Model

// doc.items : 変更対象項目が書かれた配列
// doc.items[*] : 変更対象項目
// doc.items[*].type : 0 : 属性, 1 : 子ノード
// doc.items[*].dom : 変更対象項目のdomオブジェクト type=0のときDomAttribute、type=1のときDOMElement
// doc.items[*].xpath: selectNodeで検索したときのxpath文字列
// doc.dom : xmlファイルのdomオブジェクト
var doc = { dom: new ActiveXObject('MSXML.DOMDocument'), items: };
doc.dom.async = false;
var partdom = new ActiveXObject('MSXML.DOMDocument');
partdom.async = false;

// doc.domの指定されたxpathのノードからattnameで指定した属性を探し出し、doc.itemsに追加する。
function add_attributeitems(xpath, attname) {
var nodes = doc.dom.documentElement.selectNodes(xpath);
for (var i = 0; i < nodes.length; ++i) {
var attr = nodes.item(i).attributes.getNamedItem(attname);
if (attr != null) doc.items.push({ type: 0, dom: attr, xpath: xpath });
}
}

// doc.domの指定されたxpathのノードを探し出し、doc.itemsに追加する。
function add_elementitems(xpath) {
var items = ;
var nodes = doc.dom.documentElement.selectNodes(xpath);
for (var i = 0; i < nodes.length; ++i) doc.items.push({ type: 1, dom: nodes.item(i), xpath: xpath });
}

// ファイルを読み込み、対象の属性やノードを抽出する。
function read_xml(fn) {
doc.dom.load(fn);
doc.items = [];
for (var i = 0; i < xpathes.length; ++i) {
if (xpathes[i][1] == null) add_elementitems(xpathes[i][0]);
else add_attributeitems(xpathes[i][0], xpathes[i][1]);
}
}

// 読み込まれているxmlデータをファイルに書き込む。
function write_xml(fn) {
doc.dom.save(fn);
}
</script>
</html>

*test.xml
<xml>
<tag>Hello</tag>
<tag>World</tag>
<tag><Nest/></tag>
<hoge>This is xml file.</hoge>
<text attname="hoge">attribute.</text>
<text>no attribute.</text>
<n1><n2>
<target>deep</target>
</n2></n1>
<textbox id="txt">innerText</textbox>
</xml>