XBRL for PHP の公開

※以前別の場所で書いた文章を備忘的に書き記しておきます。

【投稿年月日】2011-01-24 【ジャンル】PHP/MySQL

 先日「XBRL for PHP」というスクリプトをオープンソースという形で公開しました。xmlのお勉強(PHPで解析)の成果です。

XBRL for PHP
sourceforge.jp/projects/xbrl-php/
XBRL for PHP サンプルサイト
mzstyle.s147.xrea.com/xbrlphp/

 そもそもXBRLを解析している最中(XBRLのお勉強3 (PHPで解析))、肝心のXMLに関する自らの無理解さに愕然としたことをきっかけです。これではいけないと、XMLの名前空間や要素を簡単に解析可能なPHPのクラスを作成することにした訳です。
 
 PHP5にはSimpleXMLという便利な関数がありますが、そのままでは、名前空間や要素を解析することができません。どうするかと simplexml_load_file などでXMLファイルを読み込んで配列に格納した後、 getDocNamespaces や getNamespaces で抽出した名前空間ごとに解析する必要があります。
 具体的なソースは以下の通り。「XBRL for PHP」の「/xbrl/xml/XML.php」のXMLクラスから必要な部分を抜粋したものです。
<?php
/*
* A class for Xml Perse. PHP 5 >
*
* @author Jun Yamane <jun1969x[at]gmail.com>
* @license BSD www.opensource.org/licenses/bsd-license.html
* @version ver 0.12 (2011-01-21)
* @link sourceforge.jp/projects/xbrl-php/
*
*/

class XML {
 public $ATTR = "_attributes:";
 public $NS = "_namespace:";
 public $VAL = "_value:";
/**********************************************************
Perse Xml.
*********************************************************/
 public function perseXml($file="") {
  libxml_use_internal_errors(true);
  $doc = @simplexml_load_file($file, null, LIBXML_COMPACT|LIBXML_NOCDATA|LIBXML_NOBLANKS|LIBXML_NOENT);
  if(!is_object($doc)) {
   $err["status"] = "Failed loading XML.";
   foreach(libxml_get_errors() as $error) {
    $err["error"][] = $error->message;
   }
   return $err;
  }
  $ns = $data[$this->NS] = $doc->getDocNamespaces();
  if(!count($ns)) {
   $body = $this->_perseXmlLoop($doc, "", 1);
  }else {
   $ns = $this->_nameSpace($ns, 1);
   foreach($ns as $key=>$val) {
    $obj_attr = ($val) ? $doc->attributes($val) : $doc->attributes();
    if($obj_attr) {
     $data[$this->ATTR.$key] = $this->_perseAttributes($obj_attr);
    }
   }
   $root = $doc->getName();
   $body[$root] = $data;
   foreach($ns as $key=>$val) {
    if($obj_data = $this->_perseXmlLoop($doc, $val)) {
     $body[$root][$key] = $obj_data;
    }
   }
  }
  return $body;
 }
/**********************************************************
Name Space.
*********************************************************/
 private function _nameSpace($array="") {
  if(!array_key_exists("", $array) || !in_array("", $array)) {
   $array[""] = "";
  }
  return $array;
 }
/**********************************************************
Perse Xml Attributes.
*********************************************************/
 private function _perseAttributes($attributes="") {
  foreach($attributes as $attr) {
   $data[(string)$attr->getName()] = (string)$attr;
  }
  return $data;
 }
/**********************************************************
Perse Xml Loop.
*********************************************************/
 private function _perseXmlLoop($doc="", $vals="", $not="") {
  if(!is_object($doc)) {
   return;
  }
  $ns = $this->_nameSpace($doc->getNamespaces(true));
  $vals_ = (!$vals) ? $doc->children() : $doc->children($vals);
  foreach($vals_ as $obj_key=>$obj_val) {
   if($not===1) {
    if($obj_attr = $doc->attributes()) {
     $body[$obj_key][$this->ATTR] = $this->_perseAttributes($obj_attr);
    }
   }
   $data = "";
   foreach($ns as $key=>$val) {
    if($obj_loop = $this->_perseXmlLoop($obj_val, $val)) {
     $data[$key] = $obj_loop;
    }
   }
   if(count($ns)===1) {
    $data = $data[""];
   }
   foreach($ns as $key=>$val) {
    $obj_attr = ($val) ? $obj_val->attributes($val) : $obj_val->attributes();
    if($obj_attr) {
     $data[$this->ATTR.$key] = $this->_perseAttributes($obj_attr);
    }
   }
   if((string)$obj_val && !is_array($obj_val)) {
    $data[$this->VAL] = (string)$obj_val;
   }
   $body[$obj_key][] = $data;
  }
  return $body;
 }
}
?>
 100行ほどのシンプルなクラスですが、あらゆるXML文書の解析に対応するはずです(やや自信なし)。

 なお、上記XMLクラスに関するサンプルサイトを別途用意しましたので、ご利用にあたってはソースや事例を実際に確認することをお勧めします。

XML for PHP
mzstyle.s147.xrea.com/xmlphp/

EDIUNET | PHP/MySQL | 独り言 | 提供サービス | JavaScript