読者です 読者をやめる 読者になる 読者になる

Groovy, Scala, Ruby, PHPでのXMLパース処理 - XPath使用

XPath もしくは類似の方法を使ったXMLのパース方法を Groovy, Scala, Ruby, PHP でまとめてみた。
個人的には、XMLのパース用途では Groovy を主に使用し、状況や気分に応じて Ruby, PHP を使用するような感じだ。(ScalaXMLパース用途にはあまり使わない)

なお、パース処理は以下のような XBRL ファイルから今年度連結決算(CurrentYearConsolidatedDuration)の営業利益(OperatingIncome)を出力する事にする。

パース対象のXBRLファイル
<?xml version="1.0" encoding="UTF-8"?>
<xbrli:xbrl ・・・>
・・・
  <jpfr-t-cte:OperatingIncome decimals="-6" contextRef="CurrentYearConsolidatedDuration" unitRef="JPY">15000000000</jpfr-t-cte:OperatingIncome>
・・・
</xbrli:xbrl>

Groovy でのパース処理

Groovy では XPath の代わりに GPath を使えばよい。

def doc = new XmlSlurper().parse(new File(args[0]))

def values = doc.OperatingIncome.findAll {it.@contextRef == "CurrentYearConsolidatedDuration"}

values.each {
    println it
}

Scala でのパース処理

Scala の場合、"\" や "\\" 関数を使って XPath 風の記述が可能。

import scala.xml.XML

val xml = XML.loadFile(args(0))

val values = xml \ "OperatingIncome" filter(n => (n \ "@contextRef").text == "CurrentYearConsolidatedDuration")

//以下でも可
//val values = xml \ "OperatingIncome" filter(_.attribute("contextRef").mkString == "CurrentYearConsolidatedDuration")

//以下は不可
//val values = xml \ "OperatingIncome" filter((_ \ "@contextRef").text == "CurrentYearConsolidatedDuration")

values.map(_.text).foreach(println)

Ruby でのパース処理

Ruby では REXML を使って XPath を使用すればよい。

require "rexml/document"

doc = REXML::Document.new File.new(ARGV[0])

values = doc.get_elements("//jpfr-t-cte:OperatingIncome[@contextRef='CurrentYearConsolidatedDuration']")

values.each do |n|
    puts n.text
end

PHP でのパース処理

PHP では SimpleXML を使って XPath を使用すればよい。

<?php
$doc = simplexml_load_file($argv[1]);

$values = $doc->xpath("//jpfr-t-cte:OperatingIncome[@contextRef='CurrentYearConsolidatedDuration']");

foreach($values as $v) {
    echo "$v\n";
}