XML
News!
Kinx - 3rd Preview Release!
これまでの修正も含め、3rd Preview Release を行いました。ここで触れている Fiber の修正 も含まれてます。
しかし未だ プレビュー。もし宜しければバグ報告等頂けると大変助かります。特に今回の XML はあまりテストできていない感満載。もうちょっとテストできてから紹介しようかとも思ったものの、せっかくのプレビュー版で使い方が分からないのもどうかと思い公開することにしました。実装自体はしてあり、サンプルは動くことを確認済です。
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
今回は XML です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
XML もよく利用するのでスクリプト言語でサクッと扱いたい要素の一つ。
XML
DOMパース
Xml.parseFile()
または Xml.parseString()
を使って DOM ツリーを構築する。ファイルを読み込む場合は以下の通り。
var doc = Xml.parseFile("xmlfile.xml");
下記は文字列を直接パースする例。
var doc = Xml.parseString(%{
<?xml version="1.0" encoding="UTF-8" ?>
<artists>
<artist country="US" id="1">
<name>BON JOVI</name>
<price>2400</price>
<img file="bonjovi.jpg"/>
</artist>
<artist country="US" id="2">
<name>GUNS N ROSES</name>
<price>21000</price>
<img file="GNR.jpg"/>
</artist>
<artist country="DE" id="3">
<name>Helloween</name>
<price>2400</price>
<img file="helloween.jpg"/>
</artist>
</artists>
});
返されたドキュメント・オブジェクトは以下のメソッドを持つ。
メソッド | 内容 |
---|---|
documentElement() |
ルートドキュメントを取得 |
createElement(tagname) |
Element ノードを作成する |
createTextNode(text) |
Text ノードを作成する |
createComment(comment) |
Comment ノードを作成する |
createCdataSection(content) |
CDATA Section ノードを作成する |
createProcessingInstruction(target, data) |
Processing Instruction ノードを作成する |
createEntityReference(name) |
Entity Reference ノードを作成する |
createElementNS(nsUri, qname) |
Element ノードを名前空間を指定して作成する |
getElementById(id) |
id を指定してノードを検索する |
getElementsByTagName(tagName) |
tagName のノードを配列にして返す |
xpath(expr) |
expr の XPATH を評価し、結果を配列にして返す |
ルートノード
ルートノードは documentElement()
メソッドを使用して以下のように取得する。
var root = doc.documentElement();
XMLノード
ルートノードを含む XML ノードは以下のプロパティとメソッドを持つ。
プロパティ
プロパティ | 内容 |
---|---|
type |
ノード種別 |
name |
QName |
tagName |
タグ名 |
localName |
ローカル名 |
namespaceURI |
名前空間 URI |
prefix |
プレフィックス |
メソッド
メソッド | 内容 |
---|---|
attributes() |
属性一覧を配列で返す。 |
setAttribute(qname, value) |
属性を設定する。 |
setAttributeNS(nsUri, qname, value) |
名前空間を指定して属性を設定する。 |
removeAttribute(qname) |
属性を削除する。 |
removeAttributeNS(nsUri, localName) |
名前空間を指定して属性を削除する。 |
parentNode() |
親ノードを返す。 |
children() |
子ノードを配列で返す。 |
firstChild() |
最初の子ノードを返す。 |
lastChild() |
最後の子ノードを返す。 |
nextSibling() |
次のノードを返す。 |
previousSibling() |
前のノードを返す。 |
appendChild(node) |
子ノードにノードを追加する。 |
removeChild(node) |
子ノードからノードを削除する。 |
replaceChild(node1, node2) |
子ノードのノードを置き換える。 |
replaceNode(node) |
自分自身のノードを別のノードでを置き換える。 |
insertBefore(node) |
前のノードとしてノードを追加する。 |
insertAfter(node) |
次のノードとしてノードを追加する。 |
remove() |
ノードを削除する。 |
textContent() |
テキストを取得する。 |
innerText() |
テキストを取得する。 |
hasChildren() |
子ノードが存在すれば 1 を返す。 |
hasAttributes() |
属性があれば 1 を返す。 |
getElementById(id) |
id を指定してノードを検索する |
getElementsByTagName(tagName) |
tagName のノードを配列にして返す |
xpath(expr) |
expr の XPATH を評価し、結果を配列にして返す |
XPath
XPath は XPATH 式にマッチしたノードをノードセット(配列)の形で返す。ノードセットにも xpath()
メソッドがあり、絞り込んだノード群に対し XPATH をチェインして使うことができる。
先ほどのサンプル XML のドキュメントに対して実行。
var nodes = doc.xpath("//artist")
.xpath("price")
.map(&(p) => p.innerText());
nodes.each(&(text) => {
System.println(text);
});
結果。
2400
21000
2400
サンプル・ソース
同梱しているサンプルソースを載せておきます。説明していない Xml.Writer
とかありますが、こんな感じの DOM パースができる例ということで、参考になると思い。
function displayXml(doc, node, indent) {
System.print(" " * indent);
if (node.type == Xml.ELEMENT_NODE) {
System.print("ELEM %s" % node.name);
} else if (node.type == Xml.TEXT_NODE) {
System.print("TEXT %s" % node.value.trim());
}
var attr = node.attributes();
for (var i = 0, len = attr.length(); i < len; ++i) {
System.print("[%s=%s]" % attr[i].name % attr[i].value);
}
System.println("");
var child = node.firstChild();
while (child) {
displayXml(doc, child, indent + 1);
child = child.nextSibling();
}
}
var doc = Xml.parseString(%{
<?xml version="1.0" encoding="UTF-8" ?>
<artists>
<artist country="US" id="1">
<name>BON JOVI</name>
<price>2400</price>
<img file="bonjovi.jpg"/>
</artist>
<artist country="US" id="2">
<name>GUNS N ROSES</name>
<price>21000</price>
<img file="GNR.jpg"/>
</artist>
<artist country="DE" id="3">
<name>Helloween</name>
<price>2400</price>
<img file="helloween.jpg"/>
</artist>
</artists>
});
var root = doc.documentElement();
displayXml(doc, root);
var el = root.getElementById("3");
if (el) {
el.remove();
}
System.println("");
System.println("getElementByTagName:");
var els = root.getElementsByTagName("img");
if (els.isArray) {
els.each(&(el) => displayXml(doc, el));
}
System.println("");
System.println("XPath:");
var nodes = doc.xpath("//artist").xpath("price");
if (nodes.isArray) {
nodes.each(&(el) => displayXml(doc, el));
}
var xmlWriter = new Xml.Writer(System);
xmlWriter.write(doc);
xmlWriter.write(root);
実行結果。
ELEM artists
TEXT
ELEM artist[country=US][id=1]
TEXT
ELEM name
TEXT BON JOVI
TEXT
ELEM price
TEXT 2400
TEXT
ELEM img[file=bonjovi.jpg]
TEXT
TEXT
ELEM artist[country=US][id=2]
TEXT
ELEM name
TEXT GUNS N ROSES
TEXT
ELEM price
TEXT 21000
TEXT
ELEM img[file=GNR.jpg]
TEXT
TEXT
ELEM artist[country=DE][id=3]
TEXT
ELEM name
TEXT Helloween
TEXT
ELEM price
TEXT 2400
TEXT
ELEM img[file=helloween.jpg]
TEXT
TEXT
getElementByTagName:
ELEM img[file=bonjovi.jpg]
ELEM img[file=GNR.jpg]
XPath:
ELEM price
TEXT 2400
ELEM price
TEXT 21000
<artists>
<artist country="US" id="1">
<name>BON JOVI</name>
<price>2400</price>
<img file="bonjovi.jpg" />
</artist>
<artist country="US" id="2">
<name>GUNS N ROSES</name>
<price>21000</price>
<img file="GNR.jpg" />
</artist>
</artists>
<artists>
<artist country="US" id="1">
<name>BON JOVI</name>
<price>2400</price>
<img file="bonjovi.jpg" />
</artist>
<artist country="US" id="2">
<name>GUNS N ROSES</name>
<price>21000</price>
<img file="GNR.jpg" />
</artist>
</artists>
おわりに
XPath が使えると便利だ。
そして、XML と Zip(以前の記事)を組み合わせると、実は Xlsx ファイル(Excel ファイル)の読み書きができたりします。Xlsx ファイルは Office Open XML という名前で標準仕様化されており(色々問題もあるが)、XML ファイルを Zip で固めたものになってるので読めたりするといった具合。
ただ、実際問題として Office Open XML の全てをサポートするってのは相当量のコードになるので、すぐにできそうなのは簡易的な読み書きくらいですね。時間があればチャレンジしよう。
ではまた次回。