Index: branches/version-2_12-dev/data/class_extends/api_extends/operations/Default_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/api_extends/operations/Default_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/api_extends/operations/Default_Ex.php	(revision 21713)
@@ -0,0 +1,35 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/operations/Default.php';
+
+class API_Default_Ex extends API_Default {
+
+}
Index: branches/version-2_12-dev/data/class_extends/api_extends/operations/GetVersion_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/api_extends/operations/GetVersion_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/api_extends/operations/GetVersion_Ex.php	(revision 21713)
@@ -0,0 +1,35 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/operations/GetVersion.php';
+
+class API_GetVersion_Ex extends API_GetVersion {
+
+}
Index: branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Operation_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Operation_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Operation_Ex.php	(revision 21713)
@@ -0,0 +1,35 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Operation.php';
+
+class SC_Api_Operation_Ex extends SC_Api_Operation {
+
+}
Index: branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Utils_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Utils_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/api_extends/SC_Api_Utils_Ex.php	(revision 21713)
@@ -0,0 +1,35 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Utils.php';
+
+class SC_Api_Utils_Ex extends SC_Api_Utils {
+
+}
Index: branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Ex.php	(revision 21713)
@@ -0,0 +1,67 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_REALDIR . 'pages/api/LC_Page_Api.php';
+
+/**
+ * API のページクラス(拡張).
+ *
+ * LC_Page_Api をカスタマイズする場合はこのクラスを編集する.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Ex extends LC_Page_Api {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        parent::process();
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Xml_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Xml_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Xml_Ex.php	(revision 21713)
@@ -0,0 +1,67 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_REALDIR . 'pages/api/LC_Page_Api_Xml.php';
+
+/**
+ * API のページクラス(拡張).
+ *
+ * LC_Page_Api_Xml をカスタマイズする場合はこのクラスを編集する.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Xml_Ex extends LC_Page_Api_Xml {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        parent::process();
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Php_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Php_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Php_Ex.php	(revision 21713)
@@ -0,0 +1,67 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_REALDIR . 'pages/api/LC_Page_Api_Php.php';
+
+/**
+ * API のページクラス(拡張).
+ *
+ * LC_Page_Api_Php をカスタマイズする場合はこのクラスを編集する.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Php_Ex extends LC_Page_Api_Php {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        parent::process();
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Json_Ex.php
===================================================================
--- branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Json_Ex.php	(revision 21713)
+++ branches/version-2_12-dev/data/class_extends/page_extends/api/LC_Page_Api_Json_Ex.php	(revision 21713)
@@ -0,0 +1,67 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_REALDIR . 'pages/api/LC_Page_Api_Json.php';
+
+/**
+ * API のページクラス(拡張).
+ *
+ * LC_Page_Api_Json をカスタマイズする場合はこのクラスを編集する.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Json_Ex extends LC_Page_Api_Json {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        parent::process();
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/CartGet.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/CartGet.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/CartGet.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_CartGet extends SC_Api_Abstract {
+
+    protected $operation_name = 'CartGet';
+    protected $operation_description = 'カートの取得';
+    protected $default_auth_types = self::API_AUTH_TYPE_SESSION_TOKEN;
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/CartCreate.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/CartCreate.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/CartCreate.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_CartCreate extends SC_Api_Abstract {
+
+    protected $operation_name = 'CartCreate';
+    protected $operation_description = 'カートの新規作成';
+    protected $default_auth_types = self::API_AUTH_TYPE_SESSION_TOKEN;
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/CartClear.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/CartClear.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/CartClear.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_CartClear extends SC_Api_Abstract {
+
+    protected $operation_name = 'CartClear';
+    protected $operation_description = 'カートのクリア';
+    protected $default_auth_types = self::API_AUTH_TYPE_SESSION_TOKEN;
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/AddrFromZip.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/AddrFromZip.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/AddrFromZip.php	(revision 21713)
@@ -0,0 +1,68 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_AddrFromZip extends SC_Api_Abstract {
+
+    protected $operation_name = 'AddrFromZip';
+    protected $operation_description = '郵便番号から住所を検索します。';
+    protected $default_auth_types = self::API_AUTH_TYPE_REFERER;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $arrRequest = $this->doInitParam($arrParam);
+        if (!$this->isParamError()) {
+            $zipcode = $arrRequest['zip1'] . $arrRequest['zip2'];
+            $arrAddrList = SC_Utils_Ex::sfGetAddress($zipcode);
+            if (!SC_Utils_Ex::isBlank($arrAddrList)) {
+                $this->setResponse('Address', array(
+                            'State' => $arrAddrList[0]['state'],
+                            'City' => $arrAddrList[0]['city'],
+                            'Town' => $arrAddrList[0]['town'],
+                        )
+                    );
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+        $objFormParam->addParam('郵便番号1', 'zip1', ZIP01_LEN, 'n', array('EXIST_CHECK', 'NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('郵便番号2', 'zip2', ZIP02_LEN, 'n', array('EXIST_CHECK', 'NUM_CHECK', 'MAX_LENGTH_CHECK'));
+    }
+
+    public function getResponseGroupName() {
+        return 'AddressResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/BrowseNodeLookup.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/BrowseNodeLookup.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/BrowseNodeLookup.php	(revision 21713)
@@ -0,0 +1,114 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_BrowseNodeLookup extends SC_Api_Abstract {
+
+    protected $operation_name = 'BrowseNodeLookup';
+    protected $operation_description = 'カテゴリ取得';
+    protected $default_auth_types = self::API_AUTH_TYPE_OPEN;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $arrRequest = $this->doInitParam($arrParam);
+        if (!$this->isParamError()) {
+            $category_id = $arrRequest['BrowseNodeId'];
+            if ($category_id
+                 && !SC_Helper_DB_Ex::sfIsRecord('dtb_category', 'category_id', (array)$category_id, 'del_flg = 0')) {
+                $category_id = '0';
+            } else if (SC_Utils_Ex::isBlank($category_id)) {
+                $category_id = '0';
+            }
+            // LC_Page_Products_CategoryList::lfGetCategories() と相当類似しているので共通化したい
+            $arrCategory = null;    // 選択されたカテゴリ
+            $arrChildren = array(); // 子カテゴリ
+
+            $arrAll = SC_Helper_DB_Ex::sfGetCatTree($category_id, true);
+            foreach ($arrAll as $category) {
+                if ($category_id != 0 && $category['category_id'] == $category_id) {
+                    $arrCategory = $category;
+                    continue;
+                }
+                if ($category['parent_category_id'] != $category_id) {
+                    continue;
+                }
+
+                $arrGrandchildrenID = SC_Utils_Ex::sfGetUnderChildrenArray($arrAll, 'parent_category_id', 'category_id', $category['category_id']);
+                $category['has_children'] = count($arrGrandchildrenID) > 0;
+                $arrChildren[] = $category;
+            }
+
+            if (!SC_Utils_Ex::isBlank($arrCategory)) {
+                $arrData = array(
+                    'BrowseNodeId' => $category_id,
+                    'Name' => $arrCategory['category_name'],
+                    'PageURL' =>  HTTP_URL . 'products/list.php?category_id=' . $arr['category_id'],
+                    'has_children' => count($arrChildren) > 0
+                );
+            } else {
+                $arrData = array(
+                    'BrowseNodeId' => $category_id,
+                    'Name' => 'ホーム',
+                    'PageURL' =>  HTTP_URL,
+                    'has_children' => count($arrChildren) > 0
+                );
+            }
+
+            if (!SC_Utils_Ex::isBlank($arrChildren)) {
+                $arrData['Children'] = array();
+                foreach ($arrChildren as $category) {
+                    $arrData['Children']['BrowseNode'][] = array(
+                        'BrowseNodeId' => $category['category_id'],
+                        'Name' => $category['category_name'],
+                        'PageURL' => HTTP_URL . 'products/list.php?category_id=' . $category['category_id'],
+                        'has_children' => $category['has_children']
+                        );
+                }
+            }
+            $this->setResponse('BrowseNode', $arrData);
+
+            // TODO: Ancestors 親ノード
+            return true;
+        }
+        return false;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+        $objFormParam->addParam('対象カテゴリID', 'BrowseNodeId', INT_LEN, 'a', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('返答種別', 'ResponseGroup', INT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+    }
+
+    public function getResponseGroupName() {
+        return 'BrowseNodes';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/CartModify.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/CartModify.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/CartModify.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_CartModify extends SC_Api_Abstract {
+
+    protected $operation_name = 'CartModify';
+    protected $operation_description = 'カートの修正';
+    protected $default_auth_types = self::API_AUTH_TYPE_SESSION_TOKEN;
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/CartAdd.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/CartAdd.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/CartAdd.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_CartAdd extends SC_Api_Abstract {
+
+    protected $operation_name = 'CartAdd';
+    protected $operation_description = 'カートへの商品追加';
+    protected $default_auth_types = self::API_AUTH_TYPE_SESSION_TOKEN;
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/Default.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/Default.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/Default.php	(revision 21713)
@@ -0,0 +1,57 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_Default extends SC_Api_Abstract {
+
+    protected $operation_name = 'Default';
+    protected $operation_description = 'Default Operation';
+    protected $default_auth_types = '99';
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array('DefaultEmpty' => array());
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return array('DefaultResponse' => array());
+    }
+
+    public function getResponseGroupName() {
+        return 'DefaultResponse';
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/ItemSearch.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/ItemSearch.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/ItemSearch.php	(revision 21713)
@@ -0,0 +1,274 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_ItemSearch extends SC_Api_Abstract {
+
+    protected $operation_name = 'ItemSearch';
+    protected $operation_description = '商品検索・商品一覧情報を取得します。';
+    protected $default_auth_types = self::API_AUTH_TYPE_OPEN;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $arrRequest = $this->doInitParam($arrParam);
+        if (!$this->isParamError()) {
+
+            $masterData                 = new SC_DB_MasterData_Ex();
+            $arrSTATUS            = $masterData->getMasterData('mtb_status');
+            $arrSTATUS_IMAGE      = $masterData->getMasterData('mtb_status_image');
+
+            $objProduct = new SC_Product_Ex();
+            $arrSearchData = array(
+                'category_id' => $arrRequest['BrowseNode'],
+                'maker_name' => $arrRequest['Manufacturer'],
+                'name' => $arrRequest['Keywords'],
+                'orderby' => $arrRequest['Sort'],
+            );
+
+            $arrSearchCondition = $this->getSearchCondition($arrSearchData);
+            $disp_number = 10;
+
+            $objQuery =& SC_Query_Ex::getSingletonInstance();
+            $objQuery->setWhere($arrSearchCondition['where_for_count']);
+            $objProduct = new SC_Product_Ex();
+            $linemax = $objProduct->findProductCount($objQuery, $searchCondition['arrval']);
+            $objNavi = new SC_PageNavi_Ex($arrRequest['ItemPage'], $tpl_linemax, $disp_number);
+            $arrProducts = $this->getProductsList($arrSearchCondition, $disp_number, $objNavi->start_row, $linemax, $objProduct);
+
+            if (!SC_Utils_Ex::isBlank($arrProducts)) {
+                $arrProducts = $this->setStatusDataTo($arrProducts, $arrSTATUS, $arrSTATUS_IMAGE);
+                $arrProducts = $objProduct->setPriceTaxTo($arrProducts);
+                foreach ($arrProducts as $key=>$val) {
+                    $arrProducts[$key]['main_list_image'] = SC_Utils_Ex::sfNoImageMainList($val['main_list_image']);
+                }
+
+                $arrData = array();
+                foreach ($arrProducts as $key => $val) {
+                    $arrData[] = array(
+                        'product_id' => $val['product_id'],
+                        'DetailPageURL' => HTTP_URL . 'products/detail.php?product_id=' . $val['product_id'],
+                        'ItemAttributes' => $val
+                        );
+                }
+                $this->setResponse('Item', $arrData);
+
+                return true;
+            } else {
+                $this->addError('ItemSearch.Error', '※ 要求された情報は見つかりませんでした。');
+            }
+        }
+
+        return false;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+        $objFormParam->addParam('カテゴリID', 'BrowseNode', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('キーワード', 'Keywords', STEXT_LEN, 'a', array('SPTAB_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('メーカー名', 'Manufacturer', STEXT_LEN, 'a', array('SPTAB_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('ページ番号', 'ItemPage', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('ソート', 'Sort', STEXT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+    }
+
+    public function getResponseGroupName() {
+        return 'Items';
+    }
+
+
+    /**
+     * 商品一覧の取得
+     *
+     * @return array
+     * TODO: LC_Page_Products_List::lfGetProductsList() と共通化
+     */
+    protected function getProductsList($searchCondition, $disp_number, $startno, $linemax, &$objProduct) {
+
+        $arrOrderVal = array();
+
+        $objQuery =& SC_Query_Ex::getSingletonInstance();
+        // 表示順序
+        switch ($searchCondition['orderby']) {
+            // 販売価格が安い順
+            case 'price':
+                $objProduct->setProductsOrder('price02', 'dtb_products_class', 'ASC');
+                break;
+            // 販売価格が高い順
+            case '-price':
+                $objProduct->setProductsOrder('price02', 'dtb_products_class', 'DESC');
+                break;
+
+            // 新着順
+            case 'releasedate':
+            case 'date':
+                $objProduct->setProductsOrder('create_date', 'dtb_products', 'DESC');
+                break;
+
+            // 新着順
+            case 'releasedate':
+            case 'date':
+                $objProduct->setProductsOrder('create_date', 'dtb_products', 'ASC');
+                break;
+
+            default:
+                if (strlen($searchCondition['where_category']) >= 1) {
+                    $dtb_product_categories = '(SELECT * FROM dtb_product_categories WHERE '.$searchCondition['where_category'].')';
+                    $arrOrderVal           = $searchCondition['arrvalCategory'];
+                } else {
+                    $dtb_product_categories = 'dtb_product_categories';
+                }
+                $order = <<< __EOS__
+                    (
+                        SELECT
+                            T3.rank * 2147483648 + T2.rank
+                        FROM
+                            $dtb_product_categories T2
+                            JOIN dtb_category T3
+                                USING (category_id)
+                        WHERE T2.product_id = alldtl.product_id
+                        ORDER BY T3.rank DESC, T2.rank DESC
+                        LIMIT 1
+                    ) DESC
+                    ,product_id DESC
+__EOS__;
+                    $objQuery->setOrder($order);
+                break;
+        }
+        // 取得範囲の指定(開始行番号、行数のセット)
+        $objQuery->setLimitOffset($disp_number, $startno);
+        $objQuery->setWhere($searchCondition['where']);
+
+        // 表示すべきIDとそのIDの並び順を一気に取得
+        $arrProductId = $objProduct->findProductIdsOrder($objQuery, array_merge($searchCondition['arrval'], $arrOrderVal));
+
+        $objQuery =& SC_Query_Ex::getSingletonInstance();
+        $arrProducts = $objProduct->getListByProductIds($objQuery, $arrProductId);
+        // 規格を設定
+        $objProduct->setProductsClassByProductIds($arrProductId);
+        $arrProducts['productStatus'] = $objProduct->getProductStatus($arrProductId);
+        return $arrProducts;
+
+    }
+
+    /**
+     * 検索条件のwhere文とかを取得
+     *
+     * @return array
+     * TODO: LC_Page_Products_List:;lfGetSearchCondition() と共通化
+     */
+    protected function getSearchCondition($arrSearchData) {
+        $searchCondition = array(
+            'where'             => '',
+            'arrval'            => array(),
+            'where_category'    => '',
+            'arrvalCategory'    => array(),
+            'orderby'           => ''
+        );
+
+        // カテゴリからのWHERE文字列取得
+        if (!SC_Utils_Ex::isBlank($arrSearchData['category_id'])) {
+            list($searchCondition['where_category'], $searchCondition['arrvalCategory']) = SC_Helper_DB_Ex::sfGetCatWhere($arrSearchData['category_id']);
+        }
+        // ▼対象商品IDの抽出
+        // 商品検索条件の作成（未削除、表示）
+        $searchCondition['where'] = 'alldtl.del_flg = 0 AND alldtl.status = 1 ';
+
+        if (strlen($searchCondition['where_category']) >= 1) {
+            $searchCondition['where'] .= ' AND EXISTS (SELECT * FROM dtb_product_categories WHERE ' . $searchCondition['where_category'] . ' AND product_id = alldtl.product_id)';
+            $searchCondition['arrval'] = array_merge($searchCondition['arrval'], $searchCondition['arrvalCategory']);
+        }
+
+        // 商品名をwhere文に
+        $name = $arrSearchData['name'];
+        $name = str_replace(',', '', $name);
+        // 全角スペースを半角スペースに変換
+        $name = str_replace('　', ' ', $name);
+        // スペースでキーワードを分割
+        $names = preg_split('/ +/', $name);
+        // 分割したキーワードを一つずつwhere文に追加
+        foreach ($names as $val) {
+            if (strlen($val) > 0) {
+                $searchCondition['where']    .= ' AND ( alldtl.name ILIKE ? OR alldtl.comment3 ILIKE ?) ';
+                $searchCondition['arrval'][]  = "%$val%";
+                $searchCondition['arrval'][]  = "%$val%";
+            }
+        }
+
+        // メーカーらのWHERE文字列取得
+        if ($arrSearchData['maker_id']) {
+            $searchCondition['where']   .= ' AND alldtl.maker_id = ? ';
+            $searchCondition['arrval'][] = $arrSearchData['maker_id'];
+        }
+
+        $searchCondition['where_for_count'] = $searchCondition['where'];
+
+        // 在庫無し商品の非表示
+        if (NOSTOCK_HIDDEN) {
+            $searchCondition['where'] .= ' AND (stock >= 1 OR stock_unlimited = 1)';
+            $searchCondition['where_for_count'] .= ' AND EXISTS(SELECT * FROM dtb_products_class WHERE product_id = alldtl.product_id AND del_flg = 0 AND (stock >= 1 OR stock_unlimited = 1))';
+        }
+
+        // ソート順
+        if (!SC_Utils_Ex::isBlank($arrSearchData['orderby'])) {
+            $searchCondition['orderby'] = $arrSearchData['orderby'];
+        }
+
+        return $searchCondition;
+    }
+
+
+    /**
+     * 商品情報配列に商品ステータス情報を追加する
+     *
+     * @param Array $arrProducts 商品一覧情報
+     * @param Array $arrStatus 商品ステータス配列
+     * @param Array $arrStatusImage スタータス画像配列
+     * @return Array $arrProducts 商品一覧情報
+     */
+    protected function setStatusDataTo($arrProducts, $arrStatus, $arrStatusImage) {
+
+        foreach ($arrProducts['productStatus'] as $product_id => $arrValues) {
+            for ($i = 0; $i < count($arrValues); $i++) {
+                $product_status_id = $arrValues[$i];
+                if (!empty($product_status_id)) {
+                    $arrProductStatus = array(
+                        'status_cd' => $product_status_id,
+                        'status_name' => $arrStatus[$product_status_id],
+                        'status_image' =>$arrStatusImage[$product_status_id],
+                    );
+                    $arrProducts['productStatus'][$product_id][$i] = $arrProductStatus;
+                }
+            }
+        }
+        return $arrProducts;
+    }
+
+}
Index: branches/version-2_12-dev/data/class/api/operations/GetVersion.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/GetVersion.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/GetVersion.php	(revision 21713)
@@ -0,0 +1,58 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_GetVersion extends SC_Api_Abstract {
+
+    protected $operation_name = 'GetVersion';
+    protected $operation_description = 'EC-CUBE Version';
+    protected $default_auth_types = self::API_AUTH_TYPE_OPEN;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array(
+            'Version' => ECCUBE_VERSION);
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return;
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/operations/ItemLookup.php
===================================================================
--- branches/version-2_12-dev/data/class/api/operations/ItemLookup.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/operations/ItemLookup.php	(revision 21713)
@@ -0,0 +1,107 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class API_ItemLookup extends SC_Api_Abstract {
+
+    protected $operation_name = 'ItemLookup';
+    protected $operation_description = '商品詳細情報を取得します。';
+    protected $default_auth_types = self::API_AUTH_TYPE_OPEN;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $arrRequest = $this->doInitParam($arrParam);
+        if (!$this->isParamError()) {
+            $objProduct = new SC_Product_Ex();
+
+            switch ($arrRequest['IdType']) {
+            case 'product_code':
+                $search_column = 'product_code';
+                break;
+            case 'product_class_id':
+                $arrProduct = $objProduct->getDetailAndProductsClass($arrRequest['ItemId']);
+                break;
+            case 'product_id':
+            default:
+                $arrProduct = $objProduct->getDetail($arrRequest['ItemId']);
+                break;
+            }
+
+            $objProduct->setProductsClassByProductIds(array($arrProduct['product_id']));
+
+            if ($arrProduct['del_flg'] == '0' && $arrProduct['status'] == '1') {
+                unset($arrProduct['note']);
+                $this->setResponse('product_id', $arrProduct['product_id']);
+                $this->setResponse('DetailPageURL', HTTP_URL . 'products/detail.php?product_id=' . $arrProduct['product_id']);
+                $this->setResponse('Title', $arrProduct['name']);
+                $this->setResponse('ItemAttributes', $arrProduct);
+                return true;
+            } else {
+                $this->addError('ItemLookup.Error', '※ 要求された情報は見つかりませんでした。');
+            }
+        }
+
+        return false;
+    }
+
+    protected function checkErrorExtended($arrParam) {
+        switch ($arrParam['IdType']) {
+        case 'product_code':
+            break;
+        case 'product_id':
+        case 'product_class_id':
+        default:
+            $objErr = new SC_CheckError_Ex($arrParam);
+            $objErr->doFunc(array('指定ID', 'ItemId', INT_LEN), array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
+            $this->addError($objErr->arrErr);
+            break;
+        }
+    }
+
+    protected function lfInitParam(&$objFormParam) {
+        $objFormParam->addParam('商品コンディション', 'Condition', STEXT_LEN, 'a', array('ALNUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('商品ID種別', 'IdType', STEXT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('指定ID', 'ItemId', STEXT_LEN, 'a', array('EXIST_CHECK', 'GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('関連商品数', 'RelatedItemsPage', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('関連商品種別', 'RelationshipType', STEXT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('レビューページ番号', 'ReviewPage', INT_LEN, 'N', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('レビューページソート', 'ReviewSort', STEXT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('関連タグページ', 'TagPage', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('関連タグページ数', 'TagsPerPage', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('関連タグソート', 'TagSort', STEXT_LEN, 'a', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+    }
+
+    public function getResponseGroupName() {
+        return 'Item';
+    }
+}
Index: branches/version-2_12-dev/data/class/api/SC_Api_Operation.php
===================================================================
--- branches/version-2_12-dev/data/class/api/SC_Api_Operation.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/SC_Api_Operation.php	(revision 21713)
@@ -0,0 +1,405 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの実行処理本体
+ * 権限チェックと設定チェックを行い、APIオペレーション本体を呼び出す。
+ * 結果データの生成
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+
+
+class SC_Api_Operation {
+
+    /** API_DEBUG_MODE */
+    const API_DEBUG_MODE = false;
+
+    /** 認証タイプ */
+    const API_AUTH_TYPE_REFERER = '1';          // リファラー
+    const API_AUTH_TYPE_SESSION_TOKEN = '2';    // CSRF TOKEN
+    const API_AUTH_TYPE_API_SIGNATURE = '3';    // API 署名認証 推奨
+    const API_AUTH_TYPE_CUSTOMER = '4';         // 会員認証
+    const API_AUTH_TYPE_MEMBER = '5';           // 管理者認証
+    const API_AUTH_TYPE_CUSTOMER_LOGIN_SESSION = '6';   // 顧客ログインセッションが有効
+    const API_AUTH_TYPE_MEMBER_LOGIN_SESSION = '7';     // 管理者ログインセッションが有効
+    const API_AUTH_TYPE_IP = '8';               // IP認証
+    const API_AUTH_TYPE_HOST = '9';             // ホスト認証
+    const API_AUTH_TYPE_SSL = '10';             // SSL強制
+    const API_AUTH_TYPE_OPEN = '99';            // 完全オープン
+
+    /**
+     * 有効な管理者ID/PASSかどうかチェックする
+     *
+     * @param string $member_id ログインID文字列
+     * @param string $member_password ログインパスワード文字列
+     * @return boolean ログイン情報が有効な場合 true
+     */
+    protected function checkMemberAccount($member_id, $member_password) {
+        $objQuery =& SC_Query_Ex::getSingletonInstance();
+        //パスワード、saltの取得
+        $cols = 'password, salt';
+        $table = 'dtb_member';
+        $where = 'login_id = ? AND del_flg <> 1 AND work = 1';
+        $arrData = $objQuery->getRow($cols, $table, $where, array($login_id));
+        if (SC_Utils_Ex::isBlank($arrData)) {
+            return false;
+        }
+        // ユーザー入力パスワードの判定
+        if (SC_Utils_Ex::sfIsMatchHashPassword($pass, $arrData['password'], $arrData['salt'])) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 会員ログインチェックを実行する.
+     *
+     * @param string $login_email ログインメールアドレス
+     * @param string $password ログインパスワード
+     * @return boolean ログインに成功した場合 true; 失敗した場合 false
+     */
+    protected function checkCustomerAccount($login_email, $login_password) {
+        $objCustomer = new SC_Customer_Ex();
+        if ($objCustomer->getCustomerDataFromEmailPass($login_password, $login_email)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * リファラーチェックを実行する.
+     *
+     * @return boolean チェックに成功した場合 true; 失敗した場合 false
+     */
+    protected function checkReferer() {
+        $ret = false;
+        if(!SC_Utils_Ex::isBlank($_SERVER['HTTP_REFERER'])) {
+            $domain  = SC_Utils_Ex::sfIsHTTPS() ? HTTPS_URL : HTTP_URL;
+            $pattern = sprintf('|^%s.*|', $domain);
+            $referer = $_SERVER['HTTP_REFERER'];
+            if (preg_match($pattern, $referer)) {
+               $ret = true;
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * HMAC-SHA 署名認証チェック
+     * Refer: http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/ninshou-law/law-index.html
+     *
+     * @param  string 実行処理名
+     * @param array リクエストパラメータ
+     * @return boolean 署名認証に成功した場合 true; 失敗した場合 false
+     */
+    protected function checkApiSignature($operation_name, $arrParam, $arrApiConfig) {
+        if (SC_Utils_Ex::isBlank($arrParam['Signature'])) {
+            return false;
+        }
+        if (SC_Utils_Ex::isBlank($arrParam['Timestamp'])) {
+            return false;
+        }
+/*
+        $allow_account_id = SC_Api_Operation_Ex::getOperationSubConfig($operation_name, 'allow_account_id', $arrApiConfig);
+        if (!SC_Utils_Ex::isBlank($allow_account_id) and) {
+            $arrAllowAccountIds = explode('|', $allow_account_id);
+
+        }
+*/
+
+        $access_key = $arrParam['AccessKeyId'];
+        $secret_key = SC_Api_Operation_Ex::getApiSecretKey($access_key);
+
+        // バイト順に並び替え
+        ksort($arrParam);
+
+        // 規定の文字列フォーマットを作成する
+        // Refer: https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?Query_QueryAuth.html
+        $check_str = '';
+        foreach($arrParam as $key => $val) {
+            switch ($key) {
+                case 'Signature':
+                    break;
+                default:
+                    $check_str .= '&' . SC_Utils_Ex::encodeRFC3986($key) . '=' . SC_Utils_Ex::encodeRFC3986($val);
+                    break;
+            }
+        }
+        $check_str = substr($check_str, 1);
+        $check_str = strtoupper($_SERVER['REQUEST_METHOD']) . "\n"
+                     . strtolower($_SERVER['SERVER_NAME']) . "\n"
+                     . $_SERVER['PHP_SELF'] . "\n"
+                     . $check_str;
+
+        $signature = base64_encode(hash_hmac('sha256', $check_str, $secret_key, true));
+
+        if($signature === $arrParam['Signature']) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * IPチェックを実行する.
+     *
+     * @param  string 実行処理名
+     * @return boolean チェックに成功した場合 true; 失敗した場合 false
+     */
+    protected function checkIp($operation_name) {
+        $ret = false;
+        $allow_hosts = SC_Api_Utils_Ex::getOperationSubConfig($operation_name, 'allow_hosts');
+        $arrAllowHost = explode("\n", $allow_hosts);
+        if (is_array($arrAllowHost) && count($arrAllowHost) > 0) {
+            if (array_search($_SERVER['REMOTE_ADDR'], $arrAllowHost) !== FALSE) {
+                $ret = true;
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * ApiAccessKeyに対応した秘密鍵を取得する。
+     *
+     * @param string $access_key
+     * @return string 秘密鍵文字列
+     */
+    protected function getApiSecretKey($access_key) {
+        $objQuery =& SC_Query_Ex::getSingletonInstance();
+        $secret_key = $objQuery->get('api_secret_key', 'dtb_api_account', 'api_access_key = ? and del_flg = 0');
+        return $secret_key;
+    }
+
+    /**
+     * オペレーションの実行権限をチェックする
+     *
+     * @param string オペレーション名
+     * @param array リクエストパラメータ
+     * @return boolean 権限がある場合 true; 無い場合 false
+     */
+    protected function checkOperationAuth($operation_name, &$arrParams, &$arrApiConfig) {
+        if (SC_Utils_Ex::isBlank($operation_name)) {
+            return false;
+        }
+        $arrAuthTypes = explode("|", $arrApiConfig['auth_types']);
+        $result = false;
+        foreach ($arrAuthTypes as $auth_type) {
+            $ret = false;
+            switch ($auth_type) {
+                case self::API_AUTH_TYPE_REFERER:
+                    $ret = SC_Api_Operation_Ex::checkReferer();
+                    break;
+                case self::API_AUTH_TYPE_SESSION_TOKEN:
+                    $ret = SC_Helper_Session_Ex::isValidToken(false);
+                    break;
+                case self::API_AUTH_TYPE_API_SIGNATURE:
+                    $ret = SC_Api_Operation_Ex::checkApiSignature($operation_name, $arrParam, $arrApiConfig);
+                    break;
+                case self::API_AUTH_TYPE_CUSTOMER:
+                    $ret = SC_Api_Operation_Ex::checkCustomerAccount($arrParam['login_email'], $arrParam['login_password']);
+                    break;
+                case self::API_AUTH_TYPE_MEMBER:
+                    $ret = SC_Api_Operation_Ex::checkMemberAccount($arrParam['member_id'], $arrParam['member_password']);
+                    break;
+                case self::API_AUTH_TYPE_CUSTOMER_LOGIN_SESSION:
+                    $objCustomer = new SC_Customer_Ex();
+                    $ret = $objCustomer->isLoginSuccess();
+                    break;
+                case self::API_AUTH_TYPE_MEMBER_LOGIN_SESSION:
+                    $ret = SC_Utils_Ex::sfIsSuccess(new SC_Session_Ex(), false);
+                    break;
+                case self::API_AUTH_TYPE_IP:
+                    $ret = SC_Api_Operation_Ex::checkIp($operation_name);
+                    break;
+                case self::API_AUTH_TYPE_HOST:
+                    $ret = SC_Api_Operation_Ex::checkHost($operation_name);
+                    break;
+                case self::API_AUTH_TYPE_SSL:
+                    $ret = SC_Utils_Ex::sfIsHTTPS();
+                    break;
+                case self::API_AUTH_TYPE_OPEN:
+                    $result = true;
+                    break 2;    // foreachも抜ける
+                default:
+                    $ret = false;
+                    break;
+            }
+            if($ret === true) {
+                $result = true;
+            }else{
+                $result = false;
+                break;  // 1つでもfalseがあれば，その時点で終了
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * APIのリクエスト基本パラメーターの設定
+     *
+     * @param object SC_FormParam
+     * @return void
+     */
+    protected function setApiBaseParam(&$objFormParam) {
+        $objFormParam->addParam('Operation', 'Operation', STEXT_LEN, 'an', array('EXIST_CHECK', 'GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('Service', 'Service', STEXT_LEN, 'an', array('EXIST_CHECK', 'GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('Style', 'Style', STEXT_LEN, 'an', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('Validate', 'Validate', STEXT_LEN, 'an', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+        $objFormParam->addParam('Version', 'Version', STEXT_LEN, 'an', array('GRAPH_CHECK', 'MAX_LENGTH_CHECK'));
+    }
+
+    /**
+     * API実行
+     *
+     * @param array $arrPost リクエストパラメーター
+     * @return array( string レスポンス名, array レスポンス配列 )
+     */
+    public function doApiAction($arrPost) {
+        // 実行時間計測用
+        $start_time = microtime(true);
+
+        $objFormParam = new SC_FormParam_Ex();
+        SC_Api_Operation_Ex::setApiBaseParam($objFormParam);
+        $objFormParam->setParam($arrPost);
+        $objFormParam->convParam();
+
+        $arrErr = $objFormParam->checkError();
+        if (SC_Utils_Ex::isBlank($arrErr)) {
+            $arrParam = $objFormParam->getHashArray();
+            $operation_name = $arrParam['Operation'];
+            $service_name = $arrParam['Service'];
+            $style_name = $arrParam['Style'];
+            $validate_flag = $arrParam['Validate'];
+            $api_version = $arrParam['Version'];
+
+            SC_Api_Utils_Ex::printApiLog('access', $start_time, $operation_name);
+            // API設定のロード
+            $arrApiConfig = SC_Api_Utils_Ex::getApiConfig($operation_name);
+
+            if (SC_Api_Operation_Ex::checkOperationAuth($operation_name, $arrParam, $arrApiConfig)) {
+                SC_Api_Utils_Ex::printApiLog('Authority PASS', $start_time, $operation_name);
+
+                // オペレーション権限ＯＫ
+                // API オブジェクトをロード
+                $objApiOperation = SC_Api_Utils_Ex::loadApiOperation($operation_name, $arrParam);
+
+                if (is_object($objApiOperation) && method_exists($objApiOperation, 'doAction')) {
+                    // API オペレーション実行
+                    $operation_result = $objApiOperation->doAction($arrPost);
+
+                    // オペレーション結果処理
+                    if($operation_result) {
+                        $arrOperationRequestValid = $objApiOperation->getRequestValidate();
+                        $arrResponseBody =  $objApiOperation->getResponseArray();
+                        $response_group_name = $objApiOperation->getResponseGroupName();
+                    }else{
+                        $arrErr = $objApiOperation->getErrorArray();
+                    }
+                }else{
+                    $arrErr['ECCUBE.Operation.NoLoad'] = 'オペレーションをロード出来ませんでした。';
+                }
+            }else{
+                $arrErr['ECCUBE.Authority.NoAuthority'] = 'オペレーションの実行権限がありません。';
+            }
+        }
+
+        if (count($arrErr) == 0) {
+            // 実行成功
+            $arrResponseValidSection = array( 'Request' => array(
+                                                            'IsValid' => 'True',
+                                                            $operation_name . 'Request' => $arrOperationRequestValid
+                                                            )
+                                            );
+            $response_outer = $operation_name . 'Response';
+            SC_Api_Utils_Ex::printApiLog('Operation SUCCESS', $start_time, $response_outer);
+        } else {
+            // 実行失敗
+            $arrResponseErrorSection = array();
+            foreach ($arrErr as $error_code => $error_msg) {
+                $arrResponseErrorSection[] = array('Code' => $error_code, 'Message' => $error_msg);
+            }
+            $arrResponseValidSection = array( 'Request' => array(
+                                                            'IsValid' => 'False',
+                                                            'Errors' => array('Error' => $arrResponseErrorSection)
+                                                            )
+                                            );
+            if (is_object($objApiOperation)) {
+                $response_outer = $operation_name . 'Response';
+            }else{
+                $response_outer = 'ECCUBEApiCommonResponse';
+            }
+            SC_Api_Utils_Ex::printApiLog('Operation FAILED', $start_time, $response_outer);
+        }
+
+        $arrResponse = array();
+        $arrResponse['OperationRequest'] = SC_Api_Operation_Ex::getOperationRequestEcho($arrPost, $start_time);
+        $arrResponse[$response_group_name] = array(); // Items
+        $arrResponse[$response_group_name] = $arrResponseValidSection;
+        if (is_array($arrResponseBody)) {
+            $arrResponse[$response_group_name] = array_merge((array)$arrResponse[$response_group_name], (array)$arrResponseBody);
+        }
+
+        return array($response_outer, $arrResponse);
+    }
+
+    /**
+     * APIのリクエストのエコー情報の作成
+     *
+     * @param array $arrParam リクエストパラメーター
+     * @param float $start_time 実行時間計測用開始時間
+     * @return array エコー情報配列 (XML用の _attributes 指定入り）
+     */
+    protected function getOperationRequestEcho($arrParam, $start_time) {
+        $arrRet = array(
+                'HTTPHeaders' => array('Header' => array('_attributes' => array('Name' => 'UserAgent',
+                                                                                'Value' => htmlspecialchars($_SERVER['HTTP_USER_AGENT'])))),
+                'RequestId' => $start_time,
+                'Arguments' => array(),
+                );
+        foreach($arrParam as $key => $val) {
+            $arrRet['Arguments'][] = array('_attributes' => array('Name' => htmlentities($key, ENT_NOQUOTES, 'UTF-8'), 'Value' => htmlentities($val, ENT_NOQUOTES, 'UTF-8')));
+        }
+        $arrRet['RequestProcessingTime'] = microtime(true) - $start_time;
+        return $arrRet;
+    }
+
+    // TODO: ここらへんは SC_Displayに持って行きたい所だが・・
+    public function sendApiResponse($type, $response_outer_name, &$arrResponse) {
+        switch($type) {
+            case 'xml':
+                SC_Api_Utils_Ex::sendResponseXml($response_outer_name, $arrResponse);
+                break;
+            case 'php':
+                SC_Api_Utils_Ex::sendResponsePhp($response_outer_name, $arrResponse);
+                break;
+            case 'json':
+            default:
+                SC_Api_Utils_Ex::sendResponseJson($response_outer_name, $arrResponse);
+                break;
+        }
+    }
+
+}
Index: branches/version-2_12-dev/data/class/api/SC_Api_Utils.php
===================================================================
--- branches/version-2_12-dev/data/class/api/SC_Api_Utils.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/SC_Api_Utils.php	(revision 21713)
@@ -0,0 +1,221 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * API関係処理のユーティリティ
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+define('API_UPLOAD_REALDIR', DATA_REALDIR . "downloads/api/");
+define('API_CLASS_EX_REALDIR', CLASS_EX_REALDIR . "api_extends/operations/");
+define('API_CLASS_REALDIR', CLASS_REALDIR . "api/operations/");
+
+class SC_Api_Utils {
+
+    /** API XML Namspase */
+    const API_XMLNS = 'http://www.ec-cube.net/ECCUBEApi/';
+
+    /** API XML lang */
+    const API_XML_LANG = 'ja';
+
+    /** API LOGFILE_NAME */
+    const API_LOGFILE = 'logs/api.log';
+
+    /** API_DEBUG_MODE */
+    const API_DEBUG_MODE = false;
+
+    /**
+     * オペレーション名に対応した追加の設定情報を取得する
+     *
+     * @param string $access_key
+     * @return string 秘密鍵文字列
+     */
+    public function getOperationSubConfig($operation_name, $key_name = '', $arrApiConfig = '') {
+        if (SC_Utils_Ex::isBlank($arrApiConfig)) {
+            $arrApiConfig = SC_Api_Utils_Ex::getAuthConfig($operation_name);
+        }
+        if (!SC_Utils_Ex::isBlank($arrApiConfig['sub_data'])) {
+            $arrData = @unserialize($arrApiConfig['sub_data']);
+            if ($arrData === FALSE) {
+                return $arrApiConfig['sub_data'];
+            } else {
+                if ($key_name != '') {
+                    return $arrData['key_name'];
+                } else {
+                    return $arrData;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * オペレーション名に対応した認証の設定情報を取得する
+     * Configが無い場合は、APIデフォルトを取得する
+     *
+     * @param string $operation_name
+     * @return array 設定配列
+     */
+    public function getApiConfig($operation_name) {
+        // 設定優先度 DB > plugin default > base
+        $objQuery =& SC_Query_Ex::getSingletonInstance();
+        $where = 'operation_name Like ? AND del_flg = 0 AND enable = 1';
+        $arrApiConfig = $objQuery->getRow('*', 'dtb_api_config', $where, array($operation_name));
+        if (SC_Utils_Ex::isBlank($arrApiConfig)) {
+            $objApi = SC_Api_Utils_Ex::loadApiOperation($operation_name);
+            if (is_object($objApi)) {
+                $arrApiConfig = $objApi->getDefaultConfig();
+            }
+            if (!SC_Utils_Ex::isBlank($arrApiConfig)) {
+                // デフォルト設定がロード出来た場合は自動で設定に反映
+                $arrData = $arrApiConfig;
+                $arrData['update_date'] = 'CURRENT_TIMESTAMP';
+                $arrData['api_config_id'] = $objQuery->nextVal('dtb_api_config_api_config_id');
+                $objQuery->insert('dtb_api_config', $arrData);
+            } else {
+                // ロード出来ない場合はAPI_Defaultを適用
+                $operation_name = 'Default';
+                $objApi = SC_Api_Utils_Ex::loadApiOperation($operation_name);
+                $arrApiConfig = $objApi->getDefaultConfig();
+            }
+        }
+        return $arrApiConfig;
+    }
+
+    /**
+     * APIログ
+     *
+     * @param text $msg 出力文字列
+     * @param text $operation_name
+     @ @rturn void
+     */
+    public function printApiLog($msg, $start_time = '' , $operation_name = '') {
+        if (!SC_Utils_Ex::isBlank($operation_name)) {
+            $msg = 'API_' . $operation_name . ':' . $msg;
+        }
+        if (!SC_Utils_Ex::isBlank($start_time)) {
+            $msg = '(RequestId:' . $start_time . ')' . $msg;
+        }
+        GC_Utils_Ex::gfPrintLog($msg, DATA_REALDIR . self::API_LOGFILE, self::API_DEBUG_MODE);
+    }
+
+    /**
+     * APIオペレーションに対応したAPIクラスをインスタンス化
+     *
+     * @param string $operation_name オペレーション名
+     * @param array $arrParam リクエストパラメーター
+     * @return object APIオペレーションクラスオブジェクト
+     */
+    public function loadApiOperation($operation_name, $arrParam = array()) {
+        // API_UPLOADのほうが優先
+        // API_UPLOAD > API_CLASS_EX > API_CLASS
+        if (file_exists(API_UPLOAD_REALDIR . $operation_name . '.php')) {
+            $api_operation_file =  API_UPLOAD_REALDIR . $operation_name . '.php';
+            $api_class_name = 'API_' . $operation_name;
+        } elseif (file_exists(API_CLASS_EX_REALDIR . $operation_name . '_Ex.php')) {
+            $api_operation_file =  API_CLASS_EX_REALDIR . $operation_name . '_Ex.php';
+            $api_class_name = 'API_' . $operation_name . '_Ex';
+        } elseif (file_exists(API_CLASS_REALDIR . $operation_name . '.php')) {
+            $api_operation_file =  API_CLASS_REALDIR . $operation_name . '.php';
+            $api_class_name = 'API_' . $operation_name;
+        } else {
+            return false;
+        }
+        require_once $api_operation_file;
+        $objApiOperation = new $api_class_name ($arrParam);
+
+        return $objApiOperation;
+    }
+
+    /**
+     * API Operationファイル一覧
+     *
+     * @return array $arrFiles
+     */
+    public function getApiDirFiles() {
+        $arrFiles = array();
+        // Core API ディレクトリ
+        if (is_dir(API_CLASS_EX_REALDIR)) {
+            if($dh = opendir(API_CLASS_EX_REALDIR)) {
+                while (($file_name = readdir($dh)) !== false) {
+                    if ($file_name != '.' && $file_name != '..' && substr($file_name, -4) == '.php') {
+                        $arrFiles[] = API_CLASS_EX_REALDIR . $file_name;
+                    }
+                }
+                closedir($dh);
+            }
+        }
+
+        // downaloads APIディレクトリ (for Plugin)
+        if (is_dir(API_UPLOAD_REALDIR)) {
+            if($dh = opendir(API_UPLOAD_REALDIR)) {
+                while (($file_name = readdir($dh)) !== false) {
+                    if ($file_name != '.' && $file_name != '..' && substr($file_name, -4) == '.php') {
+                        $arrFiles[] = API_UPLOAD_REALDIR . $file_name;
+                    }
+                }
+                closedir($dh);
+            }
+        }
+        return $arrFiles;
+    }
+
+    public function sendResponseJson($response_outer_name, &$arrResponse) {
+        header('Content-Type: application/json; charset=UTF-8');
+        $arrResponse['response_name'] = $response_outer_name;
+        echo SC_Utils_Ex::jsonEncode($arrResponse);
+    }
+
+    public function sendResponsePhp($response_outer_name, &$arrResponse) {
+        header('Content-Type: application/php; charset=UTF-8');
+        $arrResponse['response_name'] = $response_outer_name;
+        echo serialize($arrResponse);
+    }
+
+    public function sendResponseXml($response_outer_name, &$arrResponse) {
+        require_once 'XML/Serializer.php';
+
+        $options = array(
+            'mode' => 'simplexml',
+            'indent' => "\t",
+            'linebreak' => "\n",
+            'typeHints' => false,
+            'addDecl' => true,
+            'encoding' => 'UTF-8',
+            'rootName' => $response_outer_name,
+            'rootAttributes' => array( 'xmlns' => self::API_XMLNS . ECCUBE_VERSION,
+                                        'xml:lang' => self::API_XML_LANG),
+            'defaultTagName' => 'Response',
+            'attributesArray' => '_attributes'
+        );
+
+        $objSerializer = new XML_Serializer($options);
+        $ret = $objSerializer->serialize($arrResponse);
+        $xml = $objSerializer->getSerializedData();
+        header('Content-Type: text/xml; charset=UTF-8');
+        echo $xml;
+    }
+
+}
Index: branches/version-2_12-dev/data/class/api/SC_Api_Abstract.php
===================================================================
--- branches/version-2_12-dev/data/class/api/SC_Api_Abstract.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/SC_Api_Abstract.php	(revision 21713)
@@ -0,0 +1,120 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの抽象クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+
+abstract class SC_Api_Abstract {
+
+    /** 認証タイプ */
+    const API_AUTH_TYPE_REFERER = '1';          // リファラー
+    const API_AUTH_TYPE_SESSION_TOKEN = '2';    // CSRF TOKEN
+    const API_AUTH_TYPE_API_SIGNATURE = '3';    // API 署名認証 推奨
+    const API_AUTH_TYPE_CUSTOMER = '4';         // 会員認証
+    const API_AUTH_TYPE_MEMBER = '5';           // 管理者認証
+    const API_AUTH_TYPE_CUSTOMER_LOGIN_SESSION = '6';   // 顧客ログインセッションが有効
+    const API_AUTH_TYPE_MEMBER_LOGIN_SESSION = '7';     // 管理者ログインセッションが有効
+    const API_AUTH_TYPE_IP = '8';               // IP認証
+    const API_AUTH_TYPE_HOST = '9';             // ホスト認証
+    const API_AUTH_TYPE_SSL = '10';             // SSL強制
+    const API_AUTH_TYPE_OPEN = '99';            // 完全オープン
+
+    /** API Operation default */
+    protected $operation_name = 'operation_name';
+    protected $operation_description = 'operation description';
+    protected $default_auth_types = '0'; // |区切り
+    protected $default_enable = '0';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    protected $status = true;
+    protected $arrErr = array();
+
+    final public function __construct() {}
+
+    final public function __destruct() {}
+
+    abstract public function doAction($arrParam);
+
+    abstract public function getResponseGroupName();
+
+    abstract protected function lfInitParam(&$objFormParam);
+
+    public function getResponseArray() {
+        return $this->arrResponse;
+    }
+
+    public function getErrorArray() {
+        return $this->arrErr;
+    }
+
+    public function getDefaultConfig() {
+        $arrApiConfig = array();
+        $arrApiConfig['operation_name'] = $this->operation_name;
+        $arrApiConfig['operation_description'] = $this->operation_description;
+        $arrApiConfig['auth_types'] = $this->default_auth_types;
+        $arrApiConfig['enable'] = $this->default_enable;
+        $arrApiConfig['is_log'] = $this->default_is_log;
+        $arrApiConfig['sub_data'] = $this->default_sub_data;
+        return $arrApiConfig;
+    }
+
+    protected function setResponse($key, $data) {
+        $this->arrResponse[$key] = $data;
+    }
+
+    protected function addError($arrErr) {
+        $this->arrErr = array_merge((array)$this->arrErr, (array)$arrErr);
+    }
+
+    protected function isParamError() {
+        return !SC_Utils_Ex::isBlank($this->arrErr);
+    }
+
+    protected function checkErrorExtended($arrParam) {
+    }
+
+    protected function doInitParam($arrParam = array()) {
+        $this->objFormParam = new SC_FormParam_Ex();
+        $this->lfInitParam($this->objFormParam);
+        $this->objFormParam->setParam($arrParam);
+        $this->objFormParam->convParam();
+        $this->arrErr = $this->objFormParam->checkError(false);
+        $this->arrErr = array_merge( (array)$this->arrErr, (array)$this->checkErrorExtended($arrParam) );
+        return $this->objFormParam->getHashArray();
+    }
+
+    public function getRequestValidate() {
+        $arrParam = $this->objFormParam->getHashArray();
+        if (!SC_Utils_Ex::isBlank($arrParam)) {
+            return $arrParam;
+        }
+        return;
+    }
+
+}
Index: branches/version-2_12-dev/data/class/api/SC_Api_GetVersion.php
===================================================================
--- branches/version-2_12-dev/data/class/api/SC_Api_GetVersion.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/api/SC_Api_GetVersion.php	(revision 21713)
@@ -0,0 +1,54 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/**
+ * APIの基本クラス
+ *
+ * @package Api
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+require_once CLASS_REALDIR . 'api/SC_Api_Abstract.php';
+
+class SC_Api_GetVersion extends SC_Api_Abstract {
+
+    protected $operation_name = 'GetVersion';
+    protected $operation_description = 'API Version (request echo)';
+    protected $default_auth_types = self::API_AUTH_TYPE_OPEN;
+    protected $default_enable = '1';
+    protected $default_is_log = '0';
+    protected $default_sub_data = '';
+
+    public function doAction($arrParam) {
+        $this->arrResponse = array('Echo' => array());
+        return true;
+    }
+
+    public function getRequestValidate() {
+        return array('Version' => array());
+    }
+
+    public function getResponseGroupName() {
+        return 'VersionResponse';
+    }
+}
Index: branches/version-2_12-dev/data/class/util/SC_Utils.php
===================================================================
--- branches/version-2_12-dev/data/class/util/SC_Utils.php	(revision 21704)
+++ branches/version-2_12-dev/data/class/util/SC_Utils.php	(revision 21713)
@@ -2077,3 +2077,16 @@
         return implode($separator, array_fill(0, $multiplier, $input));
     }
+
+    /**
+     * RFC3986に準拠したURIエンコード
+     * MEMO: PHP5.3.0未満では、~のエンコードをしてしまうための処理
+     *
+     * @param string $str 文字列
+     * @return string RFC3986エンコード文字列
+     */
+    function encodeRFC3986($str) {
+        return str_replace('%7E', '~', rawurlencode($str));
+    }
+
+
 }
Index: branches/version-2_12-dev/data/class/pages/api/LC_Page_Api.php
===================================================================
--- branches/version-2_12-dev/data/class/pages/api/LC_Page_Api.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/pages/api/LC_Page_Api.php	(revision 21713)
@@ -0,0 +1,80 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_EX_REALDIR . 'page_extends/LC_Page_Ex.php';
+require_once CLASS_EX_REALDIR . 'api_extends/SC_Api_Operation_Ex.php';
+
+/**
+ * APIのページクラス.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api extends LC_Page_Ex {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        $this->action();
+//        $this->sendResponse();
+    }
+
+    /**
+     * Page のアクション.
+     *
+     * @return void
+     */
+    function action() {
+        $arrParam = $_REQUEST;
+
+        list($response_outer, $arrResponse) = SC_Api_Operation::doApiAction($arrParam);
+        SC_Api_Operation_Ex::sendApiResponse('xml', $response_outer, $arrResponse);
+        exit;
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Xml.php
===================================================================
--- branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Xml.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Xml.php	(revision 21713)
@@ -0,0 +1,80 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_EX_REALDIR . 'page_extends/LC_Page_Ex.php';
+require_once CLASS_EX_REALDIR . 'api_extends/SC_Api_Operation_Ex.php';
+
+/**
+ * APIのページクラス.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Xml extends LC_Page_Ex {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        $this->action();
+//        $this->sendResponse();
+    }
+
+    /**
+     * Page のアクション.
+     *
+     * @return void
+     */
+    function action() {
+        $arrParam = $_REQUEST;
+
+        list($response_outer, $arrResponse) = SC_Api_Operation::doApiAction($arrParam);
+        SC_Api_Operation_Ex::sendApiResponse('xml', $response_outer, $arrResponse);
+        exit;
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Php.php
===================================================================
--- branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Php.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Php.php	(revision 21713)
@@ -0,0 +1,80 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_EX_REALDIR . 'page_extends/LC_Page_Ex.php';
+require_once CLASS_EX_REALDIR . 'api_extends/SC_Api_Operation_Ex.php';
+
+/**
+ * APIのページクラス.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Php extends LC_Page_Ex {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        $this->action();
+//        $this->sendResponse();
+    }
+
+    /**
+     * Page のアクション.
+     *
+     * @return void
+     */
+    function action() {
+        $arrParam = $_REQUEST;
+
+        list($response_outer, $arrResponse) = SC_Api_Operation::doApiAction($arrParam);
+        SC_Api_Operation_Ex::sendApiResponse('php', $response_outer, $arrResponse);
+        exit;
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Json.php
===================================================================
--- branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Json.php	(revision 21713)
+++ branches/version-2_12-dev/data/class/pages/api/LC_Page_Api_Json.php	(revision 21713)
@@ -0,0 +1,80 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_EX_REALDIR . 'page_extends/LC_Page_Ex.php';
+require_once CLASS_EX_REALDIR . 'api_extends/SC_Api_Operation_Ex.php';
+
+/**
+ * APIのページクラス.
+ *
+ * @package Page
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class LC_Page_Api_Json extends LC_Page_Ex {
+
+    // }}}
+    // {{{ functions
+
+    /**
+     * Page を初期化する.
+     *
+     * @return void
+     */
+    function init() {
+        parent::init();
+    }
+
+    /**
+     * Page のプロセス.
+     *
+     * @return void
+     */
+    function process() {
+        $this->action();
+//        $this->sendResponse();
+    }
+
+    /**
+     * Page のアクション.
+     *
+     * @return void
+     */
+    function action() {
+        $arrParam = $_REQUEST;
+
+        list($response_outer, $arrResponse) = SC_Api_Operation::doApiAction($arrParam);
+        SC_Api_Operation_Ex::sendApiResponse('json', $response_outer, $arrResponse);
+        exit;
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+}
Index: branches/version-2_12-dev/data/module/XML/Parser/Simple.php
===================================================================
--- branches/version-2_12-dev/data/module/XML/Parser/Simple.php	(revision 21713)
+++ branches/version-2_12-dev/data/module/XML/Parser/Simple.php	(revision 21713)
@@ -0,0 +1,326 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Parser
+ *
+ * XML Parser's Simple parser class 
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2002-2008 The PHP Group
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * The name of the author may not be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  XML
+ * @package   XML_Parser
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2004-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   CVS: $Id: Simple.php 265444 2008-08-24 21:48:21Z ashnazg $
+ * @link      http://pear.php.net/package/XML_Parser
+ */
+
+/**
+ * built on XML_Parser
+ */
+require_once 'XML/Parser.php';
+
+/**
+ * Simple XML parser class.
+ *
+ * This class is a simplified version of XML_Parser.
+ * In most XML applications the real action is executed,
+ * when a closing tag is found.
+ *
+ * XML_Parser_Simple allows you to just implement one callback
+ * for each tag that will receive the tag with its attributes
+ * and CData.
+ *
+ * <code>
+ * require_once '../Parser/Simple.php';
+ *
+ * class myParser extends XML_Parser_Simple
+ * {
+ *     function myParser()
+ *     {
+ *        $this->XML_Parser_Simple();
+ *      }
+ * 
+ *    function handleElement($name, $attribs, $data)
+ *     {
+ *         printf('handle %s<br>', $name);
+ *     }
+ * }
+ * 
+ * $p = &new myParser();
+ * 
+ * $result = $p->setInputFile('myDoc.xml');
+ * $result = $p->parse();
+ * </code>
+ *
+ * @category  XML
+ * @package   XML_Parser
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2004-2008 The PHP Group
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/XML_Parser
+ */
+class XML_Parser_Simple extends XML_Parser
+{
+    /**
+     * element stack
+     *
+     * @access   private
+     * @var      array
+     */
+    var $_elStack = array();
+
+    /**
+     * all character data
+     *
+     * @access   private
+     * @var      array
+     */
+    var $_data = array();
+
+    /**
+     * element depth
+     *
+     * @access   private
+     * @var      integer
+     */
+    var $_depth = 0;
+
+    /**
+     * Mapping from expat handler function to class method.
+     *
+     * @var  array
+     */
+    var $handler = array(
+        'default_handler'                   => 'defaultHandler',
+        'processing_instruction_handler'    => 'piHandler',
+        'unparsed_entity_decl_handler'      => 'unparsedHandler',
+        'notation_decl_handler'             => 'notationHandler',
+        'external_entity_ref_handler'       => 'entityrefHandler'
+    );
+    
+    /**
+     * Creates an XML parser.
+     *
+     * This is needed for PHP4 compatibility, it will
+     * call the constructor, when a new instance is created.
+     *
+     * @param string $srcenc source charset encoding, use NULL (default) to use
+     *                       whatever the document specifies
+     * @param string $mode   how this parser object should work, "event" for
+     *                       handleElement(), "func" to have it call functions
+     *                       named after elements (handleElement_$name())
+     * @param string $tgtenc a valid target encoding
+     */
+    function XML_Parser_Simple($srcenc = null, $mode = 'event', $tgtenc = null)
+    {
+        $this->XML_Parser($srcenc, $mode, $tgtenc);
+    }
+
+    /**
+     * inits the handlers
+     *
+     * @return mixed
+     * @access private
+     */
+    function _initHandlers()
+    {
+        if (!is_object($this->_handlerObj)) {
+            $this->_handlerObj = &$this;
+        }
+
+        if ($this->mode != 'func' && $this->mode != 'event') {
+            return $this->raiseError('Unsupported mode given', 
+                XML_PARSER_ERROR_UNSUPPORTED_MODE);
+        }
+        xml_set_object($this->parser, $this->_handlerObj);
+
+        xml_set_element_handler($this->parser, array(&$this, 'startHandler'), 
+            array(&$this, 'endHandler'));
+        xml_set_character_data_handler($this->parser, array(&$this, 'cdataHandler'));
+        
+        /**
+         * set additional handlers for character data, entities, etc.
+         */
+        foreach ($this->handler as $xml_func => $method) {
+            if (method_exists($this->_handlerObj, $method)) {
+                $xml_func = 'xml_set_' . $xml_func;
+                $xml_func($this->parser, $method);
+            }
+        }
+    }
+
+    /**
+     * Reset the parser.
+     *
+     * This allows you to use one parser instance
+     * to parse multiple XML documents.
+     *
+     * @access   public
+     * @return   boolean|object     true on success, PEAR_Error otherwise
+     */
+    function reset()
+    {
+        $this->_elStack = array();
+        $this->_data    = array();
+        $this->_depth   = 0;
+        
+        $result = $this->_create();
+        if ($this->isError($result)) {
+            return $result;
+        }
+        return true;
+    }
+
+    /**
+     * start handler
+     *
+     * Pushes attributes and tagname onto a stack
+     *
+     * @param resource $xp       xml parser resource
+     * @param string   $elem     element name
+     * @param array    &$attribs attributes
+     *
+     * @return mixed
+     * @access private
+     * @final
+     */
+    function startHandler($xp, $elem, &$attribs)
+    {
+        array_push($this->_elStack, array(
+            'name'    => $elem,
+            'attribs' => $attribs
+        ));
+        $this->_depth++;
+        $this->_data[$this->_depth] = '';
+    }
+
+    /**
+     * end handler
+     *
+     * Pulls attributes and tagname from a stack
+     *
+     * @param resource $xp   xml parser resource
+     * @param string   $elem element name
+     *
+     * @return mixed
+     * @access private
+     * @final
+     */
+    function endHandler($xp, $elem)
+    {
+        $el   = array_pop($this->_elStack);
+        $data = $this->_data[$this->_depth];
+        $this->_depth--;
+
+        switch ($this->mode) {
+        case 'event':
+            $this->_handlerObj->handleElement($el['name'], $el['attribs'], $data);
+            break;
+        case 'func':
+            $func = 'handleElement_' . $elem;
+            if (strchr($func, '.')) {
+                $func = str_replace('.', '_', $func);
+            }
+            if (method_exists($this->_handlerObj, $func)) {
+                call_user_func(array(&$this->_handlerObj, $func), 
+                    $el['name'], $el['attribs'], $data);
+            }
+            break;
+        }
+    }
+
+    /**
+     * handle character data
+     *
+     * @param resource $xp   xml parser resource
+     * @param string   $data data
+     *
+     * @return void
+     * @access private
+     * @final
+     */
+    function cdataHandler($xp, $data)
+    {
+        $this->_data[$this->_depth] .= $data;
+    }
+
+    /**
+     * handle a tag
+     *
+     * Implement this in your parser 
+     *
+     * @param string $name    element name
+     * @param array  $attribs attributes
+     * @param string $data    character data
+     *
+     * @return void
+     * @access public
+     * @abstract
+     */
+    function handleElement($name, $attribs, $data)
+    {
+    }
+
+    /**
+     * get the current tag depth
+     *
+     * The root tag is in depth 0.
+     *
+     * @access   public
+     * @return   integer
+     */
+    function getCurrentDepth()
+    {
+        return $this->_depth;
+    }
+
+    /**
+     * add some string to the current ddata.
+     *
+     * This is commonly needed, when a document is parsed recursively.
+     *
+     * @param string $data data to add
+     *
+     * @return void
+     * @access public
+     */
+    function addToData($data)
+    {
+        $this->_data[$this->_depth] .= $data;
+    }
+}
+?>
Index: branches/version-2_12-dev/data/module/XML/Serializer.php
===================================================================
--- branches/version-2_12-dev/data/module/XML/Serializer.php	(revision 21713)
+++ branches/version-2_12-dev/data/module/XML/Serializer.php	(revision 21713)
@@ -0,0 +1,1255 @@
+<?PHP
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Serializer
+ *
+ * Creates XML documents from PHP data structures like arrays, objects or scalars.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * The name of the author may not be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  XML
+ * @package   XML_Serializer
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   CVS: $Id: Serializer.php 294967 2010-02-12 03:10:19Z clockwerx $
+ * @link      http://pear.php.net/package/XML_Serializer
+ * @see       XML_Unserializer
+ */
+
+/**
+ * uses PEAR error management
+ */
+require_once 'PEAR.php';
+
+/**
+ * uses XML_Util to create XML tags
+ */
+require_once 'XML/Util.php';
+
+/**
+ * option: string used for indentation
+ *
+ * Possible values:
+ * - any string (default is any string)
+ */
+define('XML_SERIALIZER_OPTION_INDENT', 'indent');
+
+/**
+ * option: string used for linebreaks
+ *
+ * Possible values:
+ * - any string (default is \n)
+ */
+define('XML_SERIALIZER_OPTION_LINEBREAKS', 'linebreak');
+
+/**
+ * option: enable type hints
+ *
+ * Possible values:
+ * - true
+ * - false
+ */
+define('XML_SERIALIZER_OPTION_TYPEHINTS', 'typeHints');
+
+/**
+ * option: add an XML declaration
+ *
+ * Possible values:
+ * - true
+ * - false
+ */
+define('XML_SERIALIZER_OPTION_XML_DECL_ENABLED', 'addDecl');
+
+/**
+ * option: encoding of the document
+ *
+ * Possible values:
+ * - any valid encoding
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_XML_ENCODING', 'encoding');
+
+/**
+ * option: default name for tags
+ *
+ * Possible values:
+ * - any string (XML_Serializer_Tag is default)
+ */
+define('XML_SERIALIZER_OPTION_DEFAULT_TAG', 'defaultTagName');
+
+/**
+ * option: use classname for objects in indexed arrays
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME', 'classAsTagName');
+
+/**
+ * option: attribute where original key is stored
+ *
+ * Possible values:
+ * - any string (default is _originalKey)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
+
+/**
+ * option: attribute for type (only if typeHints => true)
+ *
+ * Possible values:
+ * - any string (default is _type)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
+
+/**
+ * option: attribute for class (only if typeHints => true)
+ *
+ * Possible values:
+ * - any string (default is _class)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
+
+/**
+ * option: scalar values (strings, ints,..) will be serialized as attribute
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ * - array which sets this option on a per-tag basis
+ */
+define('XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES', 'scalarAsAttributes');
+
+/**
+ * option: prepend string for attributes
+ *
+ * Possible values:
+ * - any string (default is any string)
+ */
+define('XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES', 'prependAttributes');
+
+/**
+ * option: indent the attributes, if set to '_auto',
+ * it will indent attributes so they all start at the same column
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ * - '_auto'
+ */
+define('XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES', 'indentAttributes');
+
+/**
+ * option: use 'simplexml' to use parent name as tagname
+ * if transforming an indexed array
+ *
+ * Possible values:
+ * - XML_SERIALIZER_MODE_DEFAULT (default)
+ * - XML_SERIALIZER_MODE_SIMPLEXML
+ */
+define('XML_SERIALIZER_OPTION_MODE', 'mode');
+
+/**
+ * option: add a doctype declaration
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_DOCTYPE_ENABLED', 'addDoctype');
+
+/**
+ * option: supply a string or an array with id and uri
+ * ({@see XML_Util::getDoctypeDeclaration()}
+ *
+ * Possible values:
+ * - string
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_DOCTYPE', 'doctype');
+
+/**
+ * option: name of the root tag
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_ROOT_NAME', 'rootName');
+
+/**
+ * option: attributes of the root tag
+ *
+ * Possible values:
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_ROOT_ATTRIBS', 'rootAttributes');
+
+/**
+ * option: all values in this key will be treated as attributes
+ *
+ * Possible values:
+ * - string
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTES_KEY', 'attributesArray');
+
+/**
+ * option: this value will be used directly as content,
+ * instead of creating a new tag, may only be used
+ * in conjuction with attributesArray
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_CONTENT_KEY', 'contentName');
+
+/**
+ * option: this value will be used in a comment, instead of creating a new tag
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_COMMENT_KEY', 'commentName');
+
+/**
+ * option: tag names that will be changed
+ *
+ * Possible values:
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_TAGMAP', 'tagMap');
+
+/**
+ * option: function that will be applied before serializing
+ *
+ * Possible values:
+ * - any valid PHP callback
+ */
+define('XML_SERIALIZER_OPTION_ENCODE_FUNC', 'encodeFunction');
+
+/**
+ * option: namespace to use for the document
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_NAMESPACE', 'namespace');
+
+/**
+ * option: type of entities to replace
+ *
+ * Possible values:
+ * - XML_SERIALIZER_ENTITIES_NONE
+ * - XML_SERIALIZER_ENTITIES_XML (default)
+ * - XML_SERIALIZER_ENTITIES_XML_REQUIRED
+ * - XML_SERIALIZER_ENTITIES_HTML
+ */
+define('XML_SERIALIZER_OPTION_ENTITIES', 'replaceEntities');
+
+/**
+ * option: whether to return the result of the serialization from serialize()
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
+
+/**
+ * option: whether to ignore properties that are set to null
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_IGNORE_NULL', 'ignoreNull');
+
+/**
+ * option: whether to use cdata sections for character data
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_CDATA_SECTIONS', 'cdata');
+
+/**
+ * option: whether a boolean FALSE value should become a string
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ *
+ * @since 0.20.0
+ */
+define('XML_SERIALIZER_OPTION_FALSE_AS_STRING', 'falseAsString');
+
+/**
+ * default mode
+ */
+define('XML_SERIALIZER_MODE_DEFAULT', 'default');
+
+/**
+ * SimpleXML mode
+ *
+ * When serializing indexed arrays, the key of the parent value is used as a tagname.
+ */
+define('XML_SERIALIZER_MODE_SIMPLEXML', 'simplexml');
+
+/**
+ * error code for no serialization done
+ */
+define('XML_SERIALIZER_ERROR_NO_SERIALIZATION', 51);
+
+/**
+ * do not replace entitites
+ */
+define('XML_SERIALIZER_ENTITIES_NONE', XML_UTIL_ENTITIES_NONE);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define('XML_SERIALIZER_ENTITIES_XML', XML_UTIL_ENTITIES_XML);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define('XML_SERIALIZER_ENTITIES_XML_REQUIRED', XML_UTIL_ENTITIES_XML_REQUIRED);
+
+/**
+ * replace HTML entitites
+ * @link    http://www.php.net/htmlentities
+ */
+define('XML_SERIALIZER_ENTITIES_HTML', XML_UTIL_ENTITIES_HTML);
+
+/**
+ * Creates XML documents from PHP data structures like arrays, objects or scalars.
+ *
+ * This class can be used in two modes:
+ *
+ *  1. Create an XML document from an array or object that is processed by other
+ *    applications. That means you can create an RDF document from an array in the
+ *    following format:
+ *    <code>
+ *    $data = array(
+ *        'channel' => array(
+ *            'title' => 'Example RDF channel',
+ *            'link'  => 'http://www.php-tools.de',
+ *            'image' => array(
+ *                'title' => 'Example image',
+ *                'url'   => 'http://www.php-tools.de/image.gif',
+ *                'link'  => 'http://www.php-tools.de'
+ *            ),
+ *            array(
+ *                'title' => 'Example item',
+ *                'link'  => 'http://example.com'
+ *            ),
+ *            array(
+ *                'title' => 'Another Example item',
+ *                'link'  => 'http://example.org'
+ *            )
+ *        )
+ *    );
+ *    </code>
+ *
+ *    To create an RDF document from this array, do the following:
+ *
+ *    <code>
+ *    require_once 'XML/Serializer.php';
+ *    $options = array(
+ *       XML_SERIALIZER_OPTION_INDENT      => "\t",     // indent with tabs
+ *       XML_SERIALIZER_OPTION_LINEBREAKS  => "\n",     // use UNIX line breaks
+ *       XML_SERIALIZER_OPTION_ROOT_NAME   => 'rdf:RDF',// root tag
+ *       XML_SERIALIZER_OPTION_DEFAULT_TAG => 'item'    // tag for values
+ *                                                      // with numeric keys
+ *    );
+ *    $serializer = new XML_Serializer($options);
+ *    $rdf        = $serializer->serialize($data);
+ *    </code>
+ *
+ *    You will get a complete XML document that can be processed like any RDF document.
+ *
+ * 2. This class can be used to serialize any data structure in a way that it can
+ *    later be unserialized again.  XML_Serializer will store the type of the value
+ *    and additional meta information in attributes of the surrounding tag. This
+ *    meta information can later be used to restore the original data structure
+ *    in PHP. If you want XML_Serializer to add meta information to the tags, add
+ *    <code>
+ *      XML_SERIALIZER_OPTION_TYPEHINTS => true
+ *    </code>
+ *    to the options array in the constructor.
+ *
+ * @category  XML
+ * @package   XML_Serializer
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/XML_Serializer
+ * @see       XML_Unserializer
+ * @todo      replace extending PEAR class with instead using a PEAR_Error object
+ */
+class XML_Serializer extends PEAR
+{
+    /**
+     * List of all available options
+     *
+     * @access private
+     * @var    array
+     */
+    var $_knownOptions = array(
+        XML_SERIALIZER_OPTION_INDENT,
+        XML_SERIALIZER_OPTION_LINEBREAKS,
+        XML_SERIALIZER_OPTION_TYPEHINTS,
+        XML_SERIALIZER_OPTION_XML_DECL_ENABLED,
+        XML_SERIALIZER_OPTION_XML_ENCODING,
+        XML_SERIALIZER_OPTION_DEFAULT_TAG,
+        XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME,
+        XML_SERIALIZER_OPTION_ATTRIBUTE_KEY,
+        XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE,
+        XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS,
+        XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES,
+        XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES,
+        XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES,
+        XML_SERIALIZER_OPTION_MODE,
+        XML_SERIALIZER_OPTION_DOCTYPE_ENABLED,
+        XML_SERIALIZER_OPTION_DOCTYPE,
+        XML_SERIALIZER_OPTION_ROOT_NAME,
+        XML_SERIALIZER_OPTION_ROOT_ATTRIBS,
+        XML_SERIALIZER_OPTION_ATTRIBUTES_KEY,
+        XML_SERIALIZER_OPTION_CONTENT_KEY,
+        XML_SERIALIZER_OPTION_COMMENT_KEY,
+        XML_SERIALIZER_OPTION_TAGMAP,
+        XML_SERIALIZER_OPTION_ENCODE_FUNC,
+        XML_SERIALIZER_OPTION_NAMESPACE,
+        XML_SERIALIZER_OPTION_ENTITIES,
+        XML_SERIALIZER_OPTION_RETURN_RESULT,
+        XML_SERIALIZER_OPTION_IGNORE_NULL,
+        XML_SERIALIZER_OPTION_CDATA_SECTIONS,
+    );
+
+    /**
+     * Default options for the serialization
+     *
+     * @access private
+     * @var    array
+     */
+    var $_defaultOptions = array(
+
+        // string used for indentation
+        XML_SERIALIZER_OPTION_INDENT => '',
+
+        // string used for newlines
+        XML_SERIALIZER_OPTION_LINEBREAKS => "\n",
+
+        // automatically add type hin attributes
+        XML_SERIALIZER_OPTION_TYPEHINTS => false,
+
+        // add an XML declaration
+        XML_SERIALIZER_OPTION_XML_DECL_ENABLED => false,
+
+        // encoding specified in the XML declaration
+        XML_SERIALIZER_OPTION_XML_ENCODING => null,
+
+        // tag used for indexed arrays or invalid names
+        XML_SERIALIZER_OPTION_DEFAULT_TAG => 'XML_Serializer_Tag',
+
+        // use classname for objects in indexed arrays
+        XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME => false,
+
+        // attribute where original key is stored
+        XML_SERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey',
+
+        // attribute for type (only if typeHints => true)
+        XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type',
+
+        // attribute for class of objects (only if typeHints => true)
+        XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class',
+
+        // scalar values (strings, ints,..) will be serialized as attribute
+        XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES => false,
+
+        // prepend string for attributes
+        XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES => '',
+
+        // indent the attributes, if set to '_auto',
+        // it will indent attributes so they all start at the same column
+        XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES => false,
+
+        // use XML_SERIALIZER_MODE_SIMPLEXML to use parent name as tagname
+        // if transforming an indexed array
+        XML_SERIALIZER_OPTION_MODE => XML_SERIALIZER_MODE_DEFAULT,
+
+        // add a doctype declaration
+        XML_SERIALIZER_OPTION_DOCTYPE_ENABLED => false,
+
+        // supply a string or an array with id and uri
+        // ({@see XML_Util::getDoctypeDeclaration()}
+        XML_SERIALIZER_OPTION_DOCTYPE => null,
+
+        // name of the root tag
+        XML_SERIALIZER_OPTION_ROOT_NAME => null,
+
+        // attributes of the root tag
+        XML_SERIALIZER_OPTION_ROOT_ATTRIBS => array(),
+
+        // all values in this key will be treated as attributes
+        XML_SERIALIZER_OPTION_ATTRIBUTES_KEY => null,
+
+        // this value will be used directly as content,
+        // instead of creating a new tag, may only be used
+        // in conjuction with attributesArray
+        XML_SERIALIZER_OPTION_CONTENT_KEY => null,
+
+        // this value will be used directly as comment,
+        // instead of creating a new tag, may only be used
+        // in conjuction with attributesArray
+        XML_SERIALIZER_OPTION_COMMENT_KEY => null,
+
+        // tag names that will be changed
+        XML_SERIALIZER_OPTION_TAGMAP => array(),
+
+        // function that will be applied before serializing
+        XML_SERIALIZER_OPTION_ENCODE_FUNC => null,
+
+        // namespace to use
+        XML_SERIALIZER_OPTION_NAMESPACE => null,
+
+        // type of entities to replace,
+        XML_SERIALIZER_OPTION_ENTITIES => XML_SERIALIZER_ENTITIES_XML,
+
+        // serialize() returns the result of the serialization instead of true
+        XML_SERIALIZER_OPTION_RETURN_RESULT => false,
+
+        // ignore properties that are set to null
+        XML_SERIALIZER_OPTION_IGNORE_NULL => false,
+
+        // Whether to use cdata sections for plain character data
+        XML_SERIALIZER_OPTION_CDATA_SECTIONS => false,
+
+        // Whether to convert a boolean FALSE into a string
+        XML_SERIALIZER_OPTION_FALSE_AS_STRING => false,
+    );
+
+    /**
+     * Options for the serialization
+     *
+     * @access public
+     * @var    array
+     */
+    var $options = array();
+
+    /**
+     * Current tag depth
+     *
+     * @access private
+     * @var    integer
+     */
+    var $_tagDepth = 0;
+
+    /**
+     * Serialized representation of the data
+     *
+     * @access private
+     * @var    string
+     */
+    var $_serializedData = null;
+
+    /**
+     * Constructor
+     *
+     * @param mixed $options array containing options for the serialization
+     *
+     * @access public
+     */
+    function XML_Serializer( $options = null )
+    {
+        $this->PEAR();
+        if (is_array($options)) {
+            $this->options = array_merge($this->_defaultOptions, $options);
+        } else {
+            $this->options = $this->_defaultOptions;
+        }
+    }
+
+    /**
+     * Return the package version number
+     *
+     * @access public
+     * @static
+     * @return string the version number of XML_Serializer
+     */
+    function apiVersion()
+    {
+        return '@package_version@';
+    }
+
+    /**
+     * Reset all options to default options
+     *
+     * @return void
+     * @access public
+     */
+    function resetOptions()
+    {
+        $this->options = $this->_defaultOptions;
+    }
+
+    /**
+     * Set an option
+     *
+     * You can use this method if you do not want
+     * to set all options in the constructor.
+     *
+     * @param string $name  option name
+     * @param mixed  $value option value
+     *
+     * @return void
+     * @access public
+     */
+    function setOption($name, $value)
+    {
+        $this->options[$name] = $value;
+    }
+
+    /**
+     * Sets several options at once
+     *
+     * You can use this method if you do not want
+     * to set all options in the constructor.
+     *
+     * @param array $options options array
+     *
+     * @return void
+     * @access public
+     */
+    function setOptions($options)
+    {
+        $this->options = array_merge($this->options, $options);
+    }
+
+    /**
+     * serialize data
+     *
+     * @param mixed $data    data to serialize
+     * @param array $options options array
+     *
+     * @return boolean true on success, pear error on failure
+     * @access public
+     * @uses XML_Util::getDoctypeDeclaration()
+     * @uses XML_Util::getXMLDeclaration()
+     * @internal uses error suppression "@settype()"
+     */
+    function serialize($data, $options = null)
+    {
+        // if options have been specified, use them instead
+        // of the previously defined ones
+        if (is_array($options)) {
+            $optionsBak = $this->options;
+            if (isset($options['overrideOptions'])
+                && $options['overrideOptions'] == true
+            ) {
+                $this->options = array_merge($this->_defaultOptions, $options);
+            } else {
+                $this->options = array_merge($this->options, $options);
+            }
+        } else {
+            $optionsBak = null;
+        }
+
+        //  start depth is zero
+        $this->_tagDepth = 0;
+
+        $rootAttributes = $this->options[XML_SERIALIZER_OPTION_ROOT_ATTRIBS];
+        if (isset($this->options[XML_SERIALIZER_OPTION_NAMESPACE])
+            && is_array($this->options[XML_SERIALIZER_OPTION_NAMESPACE])
+        ) {
+            $rootAttributes['xmlns:'
+                . $this->options[XML_SERIALIZER_OPTION_NAMESPACE][0]] =
+                $this->options[XML_SERIALIZER_OPTION_NAMESPACE][1];
+        }
+
+        $this->_serializedData = '';
+        // serialize an array
+        if (is_array($data)) {
+            if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+                $tagName = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+            } else {
+                $tagName = 'array';
+            }
+
+            $this->_serializedData .=
+                $this->_serializeArray($data, $tagName, $rootAttributes);
+        } elseif (is_object($data)) {
+            // serialize an object
+            if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+                $tagName = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+            } else {
+                $tagName = get_class($data);
+            }
+            $this->_serializedData .=
+                $this->_serializeObject($data, $tagName, $rootAttributes);
+        } else {
+            $tag = array();
+            if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+                $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+            } else {
+                $tag['qname'] = gettype($data);
+            }
+            $tagName = $tag['qname'];
+            if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+                $rootAttributes[$this->
+                    options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = gettype($data);
+            }
+
+            if (!is_bool($data)) {
+                $tag['content'] = $data;
+            } elseif ($data === false) {
+                if ($this->options[XML_SERIALIZER_OPTION_FALSE_AS_STRING] === true) {
+                    $tag['content'] = '0';
+                } else {
+                    $tag['content'] = '';
+                }
+            } else {
+                $tag['content'] = $data;
+            }
+
+            @settype($data, 'string');
+            $tag['attributes']     = $rootAttributes;
+            $this->_serializedData = $this->_createXMLTag($tag);
+        }
+
+        // add doctype declaration
+        if ($this->options[XML_SERIALIZER_OPTION_DOCTYPE_ENABLED] === true) {
+            $this->_serializedData =
+                XML_Util::getDoctypeDeclaration($tagName,
+                $this->options[XML_SERIALIZER_OPTION_DOCTYPE])
+                . $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]
+                . $this->_serializedData;
+        }
+
+        //  build xml declaration
+        if ($this->options[XML_SERIALIZER_OPTION_XML_DECL_ENABLED]) {
+            $atts                  = array();
+            $this->_serializedData = XML_Util::getXMLDeclaration('1.0',
+                $this->options[XML_SERIALIZER_OPTION_XML_ENCODING])
+                . $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]
+                . $this->_serializedData;
+        }
+
+        if ($this->options[XML_SERIALIZER_OPTION_RETURN_RESULT] === true) {
+            $result = $this->_serializedData;
+        } else {
+            $result = true;
+        }
+
+        if ($optionsBak !== null) {
+            $this->options = $optionsBak;
+        }
+
+        return $result;
+    }
+
+    /**
+     * get the result of the serialization
+     *
+     * @access public
+     * @return string serialized XML
+     */
+    function getSerializedData()
+    {
+        if ($this->_serializedData == null) {
+            return $this->raiseError('No serialized data available. '
+                . 'Use XML_Serializer::serialize() first.',
+                XML_SERIALIZER_ERROR_NO_SERIALIZATION);
+        }
+        return $this->_serializedData;
+    }
+
+    /**
+     * serialize any value
+     *
+     * This method checks for the type of the value and calls the appropriate method
+     *
+     * @param mixed  $value      tag value
+     * @param string $tagName    tag name
+     * @param array  $attributes attributes
+     *
+     * @return string
+     * @access private
+     */
+    function _serializeValue($value, $tagName = null, $attributes = array())
+    {
+        if (is_array($value)) {
+            $xml = $this->_serializeArray($value, $tagName, $attributes);
+        } elseif (is_object($value)) {
+            $xml = $this->_serializeObject($value, $tagName);
+        } else {
+            $tag = array(
+                          'qname'      => $tagName,
+                          'attributes' => $attributes,
+                          'content'    => $value
+                        );
+            $xml = $this->_createXMLTag($tag);
+        }
+        return $xml;
+    }
+
+    /**
+     * serialize an array
+     *
+     * @param array  &$array     array to serialize
+     * @param string $tagName    name of the root tag
+     * @param array  $attributes attributes for the root tag
+     *
+     * @return string $string serialized data
+     * @access private
+     * @uses XML_Util::isValidName() to check, whether key has to be substituted
+     * @uses XML_Util::replaceEntities()
+     * @uses XML_Util::createComment()
+     * @uses PEAR::popExpect()
+     * @uses PEAR::expectError()
+     */
+    function _serializeArray(&$array, $tagName = null, $attributes = array())
+    {
+        $_content = null;
+        $_comment = null;
+
+        // check for comment
+        if ($this->options[XML_SERIALIZER_OPTION_COMMENT_KEY] !== null) {
+            if (isset($array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]])
+            ) {
+                $_comment =
+                    $array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]];
+                unset($array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]]);
+            }
+        }
+
+        /**
+         * check for special attributes
+         */
+        if ($this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY] !== null) {
+            if (isset($array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]])
+            ) {
+                $attributes =
+                    $array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]];
+                unset($array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]]);
+            }
+            /**
+             * check for special content
+             */
+            if ($this->options[XML_SERIALIZER_OPTION_CONTENT_KEY] !== null) {
+                if (isset($array[$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]])
+                ) {
+                    $_content =
+                        XML_Util::replaceEntities($array
+                        [$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]]);
+                    unset($array[$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]]);
+                }
+            }
+        }
+
+        if ($this->options[XML_SERIALIZER_OPTION_IGNORE_NULL] === true) {
+            foreach (array_keys($array) as $key) {
+                if (is_null($array[$key])) {
+                    unset($array[$key]);
+                }
+            }
+        }
+
+        /*
+        * if mode is set to simpleXML, check whether
+        * the array is associative or indexed
+        */
+        if (is_array($array) && !empty($array)
+            && $this->options[XML_SERIALIZER_OPTION_MODE]
+            == XML_SERIALIZER_MODE_SIMPLEXML
+        ) {
+            $indexed = true;
+            foreach ($array as $key => $val) {
+                if (!is_int($key)) {
+                    $indexed = false;
+                    break;
+                }
+            }
+
+            if ($indexed
+                && $this->options[XML_SERIALIZER_OPTION_MODE]
+                == XML_SERIALIZER_MODE_SIMPLEXML
+            ) {
+                $string = '';
+                foreach ($array as $key => $val) {
+                    $string .= $this->_serializeValue($val, $tagName, $attributes);
+
+                    $string .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+                    // do indentation
+                    if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null
+                        && $this->_tagDepth>0
+                    ) {
+                        $string .=
+                            str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT],
+                            $this->_tagDepth);
+                    }
+                }
+                return rtrim($string);
+            }
+        }
+
+        $scalarAsAttributes = false;
+        if (is_array($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES])
+            && isset($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES]
+            [$tagName])
+        ) {
+            $scalarAsAttributes =
+                $this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES][$tagName];
+        } elseif ($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES] === true
+        ) {
+            $scalarAsAttributes = true;
+        }
+
+        if ($scalarAsAttributes === true) {
+            $this->expectError('*');
+            foreach ($array as $key => $value) {
+                if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+                    unset($array[$key]);
+                    $attributes[$this->options
+                        [XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES].$key] = $value;
+                }
+            }
+            $this->popExpect();
+        } elseif (is_array($scalarAsAttributes)) {
+            $this->expectError('*');
+            foreach ($scalarAsAttributes as $key) {
+                if (!isset($array[$key])) {
+                    continue;
+                }
+                $value = $array[$key];
+                if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+                    unset($array[$key]);
+                    $attributes[$this->options
+                        [XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES].$key] = $value;
+                }
+            }
+            $this->popExpect();
+        }
+
+        // check for empty array => create empty tag
+        if (empty($array)) {
+            $tag = array(
+                            'qname'      => $tagName,
+                            'content'    => $_content,
+                            'attributes' => $attributes
+                        );
+        } else {
+            $this->_tagDepth++;
+            $tmp = $_content . $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+            foreach ($array as $key => $value) {
+                // do indentation
+                if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null
+                    && $this->_tagDepth>0
+                ) {
+                    $tmp .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT],
+                        $this->_tagDepth);
+                }
+
+                // copy key
+                $origKey = $key;
+                $this->expectError('*');
+                // key cannot be used as tagname => use default tag
+                $valid = XML_Util::isValidName($key);
+                $this->popExpect();
+                if (PEAR::isError($valid)) {
+                    if ($this->options[XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME]
+                        && is_object($value)
+                    ) {
+                        $key = get_class($value);
+                    } else {
+                        $key = $this->_getDefaultTagname($tagName);
+                    }
+                }
+
+                // once we've established the true $key, is there a tagmap for it?
+                if (isset($this->options[XML_SERIALIZER_OPTION_TAGMAP][$key])) {
+                    $key = $this->options[XML_SERIALIZER_OPTION_TAGMAP][$key];
+                }
+
+                $atts = array();
+                if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+                    $atts[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] =
+                        gettype($value);
+                    if ($key !== $origKey) {
+                        $atts[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_KEY]] =
+                            (string)$origKey;
+                    }
+                }
+
+                $tmp .= $this->_createXMLTag(array(
+                    'qname'      => $key,
+                    'attributes' => $atts,
+                    'content'    => $value
+                ));
+                $tmp .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+            }
+
+            $this->_tagDepth--;
+            if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null
+                && $this->_tagDepth>0
+            ) {
+                $tmp .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT],
+                    $this->_tagDepth);
+            }
+
+            if (trim($tmp) === '') {
+                $tmp = null;
+            }
+
+            $tag = array(
+                          'qname'      => $tagName,
+                          'content'    => $tmp,
+                          'attributes' => $attributes
+                        );
+        }
+        if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+            if (!isset($tag['attributes']
+                [$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]])
+            ) {
+                $tag['attributes']
+                    [$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = 'array';
+            }
+        }
+
+        $string = '';
+        if (!is_null($_comment)) {
+            $string .= XML_Util::createComment($_comment);
+            $string .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+            if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null
+                && $this->_tagDepth>0
+            ) {
+                $string .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT],
+                    $this->_tagDepth);
+            }
+        }
+        $string .= $this->_createXMLTag($tag, false);
+        return $string;
+    }
+
+    /**
+     * get the name of the default tag.
+     *
+     * The name of the parent tag needs to be passed as the
+     * default name can depend on the context.
+     *
+     * @param string $parent name of the parent tag
+     *
+     * @return string default tag name
+     */
+    function _getDefaultTagname($parent)
+    {
+        if (is_string($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG])) {
+            return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG];
+        }
+        if (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG][$parent])) {
+            return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG][$parent];
+        } elseif (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]
+            ['#default'])
+        ) {
+            return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['#default'];
+        } elseif (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]
+            ['__default'])
+        ) {
+            // keep this for BC
+            return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['__default'];
+        }
+        return 'XML_Serializer_Tag';
+    }
+
+    /**
+     * serialize an object
+     *
+     * @param object &$object    object to serialize
+     * @param string $tagName    tag name
+     * @param array  $attributes attributes
+     *
+     * @return string $string serialized data
+     * @access private
+     */
+    function _serializeObject(&$object, $tagName = null, $attributes = array())
+    {
+        // check for magic function
+        if (method_exists($object, '__sleep')) {
+            $propNames = $object->__sleep();
+            if (is_array($propNames)) {
+                $properties = array();
+                foreach ($propNames as $propName) {
+                    $properties[$propName] = $object->$propName;
+                }
+            } else {
+                $properties = get_object_vars($object);
+            }
+        } else {
+            $properties = get_object_vars($object);
+        }
+
+        if (empty($tagName)) {
+            $tagName = get_class($object);
+        }
+
+        // typehints activated?
+        if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+            $attributes[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]]  =
+                'object';
+            $attributes[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS]] =
+                get_class($object);
+        }
+        $string = $this->_serializeArray($properties, $tagName, $attributes);
+        return $string;
+    }
+
+    /**
+     * create a tag from an array
+     * this method awaits an array in the following format
+     * array(
+     *       'qname'        => $tagName,
+     *       'attributes'   => array(),
+     *       'content'      => $content,      // optional
+     *       'namespace'    => $namespace     // optional
+     *       'namespaceUri' => $namespaceUri  // optional
+     *   )
+     *
+     * @param array   $tag       tag definition
+     * @param boolean $firstCall whether or not this is the first call
+     *
+     * @return string $string XML tag
+     * @access private
+     */
+    function _createXMLTag($tag, $firstCall = true)
+    {
+        // build fully qualified tag name
+        if ($this->options[XML_SERIALIZER_OPTION_NAMESPACE] !== null) {
+            if (is_array($this->options[XML_SERIALIZER_OPTION_NAMESPACE])) {
+                $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_NAMESPACE][0]
+                    . ':' . $tag['qname'];
+            } else {
+                $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_NAMESPACE]
+                    . ':' . $tag['qname'];
+            }
+        }
+
+        // attribute indentation
+        if ($this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES] !== false) {
+            $multiline = true;
+            $indent    = str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT],
+                $this->_tagDepth);
+
+            if ($this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES] == '_auto') {
+                $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
+
+            } else {
+                $indent .= $this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES];
+            }
+        } else {
+            $multiline = false;
+            $indent    = false;
+        }
+
+        if (is_array($tag['content'])) {
+            if (empty($tag['content'])) {
+                $tag['content'] =   '';
+            }
+} elseif (XML_SERIALIZER_OPTION_FALSE_AS_STRING && $tag['content'] === false) {
+$tag['content'] = '0';
+        } elseif (is_scalar($tag['content']) && (string)$tag['content'] == '') {
+            $tag['content'] =   '';
+        }
+
+        // replace XML entities
+        if ($firstCall === true) {
+            if ($this->options[XML_SERIALIZER_OPTION_CDATA_SECTIONS] === true) {
+                $replaceEntities = XML_UTIL_CDATA_SECTION;
+            } else {
+                $replaceEntities = $this->options[XML_SERIALIZER_OPTION_ENTITIES];
+            }
+        } else {
+            // this is a nested call, so value is already encoded
+            // and must not be encoded again
+            $replaceEntities = XML_SERIALIZER_ENTITIES_NONE;
+            // but attributes need to be encoded anyways
+            // (done here because the rest of the code assumes the same encoding
+            // can be used both for attributes and content)
+            foreach ($tag['attributes'] as $k => $v) {
+                $v = XML_Util::replaceEntities($v,
+                    $this->options[XML_SERIALIZER_OPTION_ENTITIES]);
+
+                $tag['attributes'][$k] = $v;
+            }
+        }
+        if (is_scalar($tag['content']) || is_null($tag['content'])) {
+            if ($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC]) {
+                if ($firstCall === true) {
+                    $tag['content'] = call_user_func($this->
+                        options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['content']);
+                }
+                $tag['attributes'] = array_map($this->
+                    options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['attributes']);
+            }
+            $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline,
+                $indent, $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]);
+        } elseif (is_array($tag['content'])) {
+            $tag = $this->_serializeArray($tag['content'], $tag['qname'],
+                $tag['attributes']);
+        } elseif (is_object($tag['content'])) {
+            $tag = $this->_serializeObject($tag['content'], $tag['qname'],
+                $tag['attributes']);
+        } elseif (is_resource($tag['content'])) {
+            settype($tag['content'], 'string');
+            if ($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC]) {
+                if ($replaceEntities === true) {
+                    $tag['content'] = call_user_func($this->
+                        options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['content']);
+                }
+                $tag['attributes'] = array_map($this->
+                    options[XML_SERIALIZER_OPTION_ENCODE_FUNC],
+                    $tag['attributes']);
+            }
+            $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
+        }
+        return  $tag;
+    }
+}
+?>
Index: branches/version-2_12-dev/data/module/XML/Parser.php
===================================================================
--- branches/version-2_12-dev/data/module/XML/Parser.php	(revision 21713)
+++ branches/version-2_12-dev/data/module/XML/Parser.php	(revision 21713)
@@ -0,0 +1,768 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Parser
+ *
+ * XML Parser package
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2002-2008 The PHP Group
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * The name of the author may not be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  XML
+ * @package   XML_Parser
+ * @author    Stig Bakken <ssb@fast.no>
+ * @author    Tomas V.V.Cox <cox@idecnet.com>
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2002-2008 The PHP Group
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   CVS: $Id: Parser.php 302733 2010-08-24 01:09:09Z clockwerx $
+ * @link      http://pear.php.net/package/XML_Parser
+ */
+
+/**
+ * uses PEAR's error handling
+ */
+require_once 'PEAR.php';
+
+/**
+ * resource could not be created
+ */
+define('XML_PARSER_ERROR_NO_RESOURCE', 200);
+
+/**
+ * unsupported mode
+ */
+define('XML_PARSER_ERROR_UNSUPPORTED_MODE', 201);
+
+/**
+ * invalid encoding was given
+ */
+define('XML_PARSER_ERROR_INVALID_ENCODING', 202);
+
+/**
+ * specified file could not be read
+ */
+define('XML_PARSER_ERROR_FILE_NOT_READABLE', 203);
+
+/**
+ * invalid input
+ */
+define('XML_PARSER_ERROR_INVALID_INPUT', 204);
+
+/**
+ * remote file cannot be retrieved in safe mode
+ */
+define('XML_PARSER_ERROR_REMOTE', 205);
+
+/**
+ * XML Parser class.
+ *
+ * This is an XML parser based on PHP's "xml" extension,
+ * based on the bundled expat library.
+ *
+ * Notes:
+ * - It requires PHP 4.0.4pl1 or greater
+ * - From revision 1.17, the function names used by the 'func' mode
+ *   are in the format "xmltag_$elem", for example: use "xmltag_name"
+ *   to handle the <name></name> tags of your xml file.
+ *          - different parsing modes
+ *
+ * @category  XML
+ * @package   XML_Parser
+ * @author    Stig Bakken <ssb@fast.no>
+ * @author    Tomas V.V.Cox <cox@idecnet.com>
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2002-2008 The PHP Group
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/XML_Parser
+ * @todo      create XML_Parser_Namespace to parse documents with namespaces
+ * @todo      create XML_Parser_Pull
+ * @todo      Tests that need to be made:
+ *            - mixing character encodings
+ *            - a test using all expat handlers
+ *            - options (folding, output charset)
+ */
+class XML_Parser extends PEAR
+{
+    // {{{ properties
+
+    /**
+     * XML parser handle
+     *
+     * @var  resource
+     * @see  xml_parser_create()
+     */
+    var $parser;
+
+    /**
+     * File handle if parsing from a file
+     *
+     * @var  resource
+     */
+    var $fp;
+
+    /**
+     * Whether to do case folding
+     *
+     * If set to true, all tag and attribute names will
+     * be converted to UPPER CASE.
+     *
+     * @var  boolean
+     */
+    var $folding = true;
+
+    /**
+     * Mode of operation, one of "event" or "func"
+     *
+     * @var  string
+     */
+    var $mode;
+
+    /**
+     * Mapping from expat handler function to class method.
+     *
+     * @var  array
+     */
+    var $handler = array(
+        'character_data_handler'            => 'cdataHandler',
+        'default_handler'                   => 'defaultHandler',
+        'processing_instruction_handler'    => 'piHandler',
+        'unparsed_entity_decl_handler'      => 'unparsedHandler',
+        'notation_decl_handler'             => 'notationHandler',
+        'external_entity_ref_handler'       => 'entityrefHandler'
+    );
+
+    /**
+     * source encoding
+     *
+     * @var string
+     */
+    var $srcenc;
+
+    /**
+     * target encoding
+     *
+     * @var string
+     */
+    var $tgtenc;
+
+    /**
+     * handler object
+     *
+     * @var object
+     */
+    var $_handlerObj;
+
+    /**
+     * valid encodings
+     *
+     * @var array
+     */
+    var $_validEncodings = array('ISO-8859-1', 'UTF-8', 'US-ASCII');
+
+    // }}}
+    // {{{ php4 constructor
+
+    /**
+     * Creates an XML parser.
+     *
+     * This is needed for PHP4 compatibility, it will
+     * call the constructor, when a new instance is created.
+     *
+     * @param string $srcenc source charset encoding, use NULL (default) to use
+     *                       whatever the document specifies
+     * @param string $mode   how this parser object should work, "event" for
+     *                       startelement/endelement-type events, "func"
+     *                       to have it call functions named after elements
+     * @param string $tgtenc a valid target encoding
+     */
+    function XML_Parser($srcenc = null, $mode = 'event', $tgtenc = null)
+    {
+        XML_Parser::__construct($srcenc, $mode, $tgtenc);
+    }
+    // }}}
+    // {{{ php5 constructor
+
+    /**
+     * PHP5 constructor
+     *
+     * @param string $srcenc source charset encoding, use NULL (default) to use
+     *                       whatever the document specifies
+     * @param string $mode   how this parser object should work, "event" for
+     *                       startelement/endelement-type events, "func"
+     *                       to have it call functions named after elements
+     * @param string $tgtenc a valid target encoding
+     */
+    function __construct($srcenc = null, $mode = 'event', $tgtenc = null)
+    {
+        $this->PEAR('XML_Parser_Error');
+
+        $this->mode   = $mode;
+        $this->srcenc = $srcenc;
+        $this->tgtenc = $tgtenc;
+    }
+    // }}}
+
+    /**
+     * Sets the mode of the parser.
+     *
+     * Possible modes are:
+     * - func
+     * - event
+     *
+     * You can set the mode using the second parameter
+     * in the constructor.
+     *
+     * This method is only needed, when switching to a new
+     * mode at a later point.
+     *
+     * @param string $mode mode, either 'func' or 'event'
+     *
+     * @return boolean|object  true on success, PEAR_Error otherwise
+     * @access public
+     */
+    function setMode($mode)
+    {
+        if ($mode != 'func' && $mode != 'event') {
+            $this->raiseError('Unsupported mode given', 
+                XML_PARSER_ERROR_UNSUPPORTED_MODE);
+        }
+
+        $this->mode = $mode;
+        return true;
+    }
+
+    /**
+     * Sets the object, that will handle the XML events
+     *
+     * This allows you to create a handler object independent of the
+     * parser object that you are using and easily switch the underlying
+     * parser.
+     *
+     * If no object will be set, XML_Parser assumes that you
+     * extend this class and handle the events in $this.
+     *
+     * @param object &$obj object to handle the events
+     *
+     * @return boolean will always return true
+     * @access public
+     * @since v1.2.0beta3
+     */
+    function setHandlerObj(&$obj)
+    {
+        $this->_handlerObj = &$obj;
+        return true;
+    }
+
+    /**
+     * Init the element handlers
+     *
+     * @return mixed
+     * @access private
+     */
+    function _initHandlers()
+    {
+        if (!is_resource($this->parser)) {
+            return false;
+        }
+
+        if (!is_object($this->_handlerObj)) {
+            $this->_handlerObj = &$this;
+        }
+        switch ($this->mode) {
+
+        case 'func':
+            xml_set_object($this->parser, $this->_handlerObj);
+            xml_set_element_handler($this->parser, 
+                array(&$this, 'funcStartHandler'), array(&$this, 'funcEndHandler'));
+            break;
+
+        case 'event':
+            xml_set_object($this->parser, $this->_handlerObj);
+            xml_set_element_handler($this->parser, 'startHandler', 'endHandler');
+            break;
+        default:
+            return $this->raiseError('Unsupported mode given', 
+                XML_PARSER_ERROR_UNSUPPORTED_MODE);
+            break;
+        }
+
+        /**
+         * set additional handlers for character data, entities, etc.
+         */
+        foreach ($this->handler as $xml_func => $method) {
+            if (method_exists($this->_handlerObj, $method)) {
+                $xml_func = 'xml_set_' . $xml_func;
+                $xml_func($this->parser, $method);
+            }
+        }
+    }
+
+    // {{{ _create()
+
+    /**
+     * create the XML parser resource
+     *
+     * Has been moved from the constructor to avoid
+     * problems with object references.
+     *
+     * Furthermore it allows us returning an error
+     * if something fails.
+     *
+     * NOTE: uses '@' error suppresion in this method
+     *
+     * @return bool|PEAR_Error true on success, PEAR_Error otherwise
+     * @access private
+     * @see xml_parser_create
+     */
+    function _create()
+    {
+        if ($this->srcenc === null) {
+            $xp = @xml_parser_create();
+        } else {
+            $xp = @xml_parser_create($this->srcenc);
+        }
+        if (is_resource($xp)) {
+            if ($this->tgtenc !== null) {
+                if (!@xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING, 
+                    $this->tgtenc)
+                ) {
+                    return $this->raiseError('invalid target encoding', 
+                        XML_PARSER_ERROR_INVALID_ENCODING);
+                }
+            }
+            $this->parser = $xp;
+            $result       = $this->_initHandlers($this->mode);
+            if ($this->isError($result)) {
+                return $result;
+            }
+            xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, $this->folding);
+            return true;
+        }
+        if (!in_array(strtoupper($this->srcenc), $this->_validEncodings)) {
+            return $this->raiseError('invalid source encoding', 
+                XML_PARSER_ERROR_INVALID_ENCODING);
+        }
+        return $this->raiseError('Unable to create XML parser resource.', 
+            XML_PARSER_ERROR_NO_RESOURCE);
+    }
+
+    // }}}
+    // {{{ reset()
+
+    /**
+     * Reset the parser.
+     *
+     * This allows you to use one parser instance
+     * to parse multiple XML documents.
+     *
+     * @access   public
+     * @return   boolean|object     true on success, PEAR_Error otherwise
+     */
+    function reset()
+    {
+        $result = $this->_create();
+        if ($this->isError($result)) {
+            return $result;
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ setInputFile()
+
+    /**
+     * Sets the input xml file to be parsed
+     *
+     * @param string $file Filename (full path)
+     *
+     * @return resource fopen handle of the given file
+     * @access public
+     * @throws XML_Parser_Error
+     * @see setInput(), setInputString(), parse()
+     */
+    function setInputFile($file)
+    {
+        /**
+         * check, if file is a remote file
+         */
+        if (preg_match('/^(http|ftp):\/\//i', substr($file, 0, 10))) {
+            if (!ini_get('allow_url_fopen')) {
+                return $this->
+                raiseError('Remote files cannot be parsed, as safe mode is enabled.',
+                XML_PARSER_ERROR_REMOTE);
+            }
+        }
+
+        $fp = @fopen($file, 'rb');
+        if (is_resource($fp)) {
+            $this->fp = $fp;
+            return $fp;
+        }
+        return $this->raiseError('File could not be opened.', 
+            XML_PARSER_ERROR_FILE_NOT_READABLE);
+    }
+
+    // }}}
+    // {{{ setInputString()
+
+    /**
+     * XML_Parser::setInputString()
+     *
+     * Sets the xml input from a string
+     *
+     * @param string $data a string containing the XML document
+     *
+     * @return null
+     */
+    function setInputString($data)
+    {
+        $this->fp = $data;
+        return null;
+    }
+
+    // }}}
+    // {{{ setInput()
+
+    /**
+     * Sets the file handle to use with parse().
+     *
+     * You should use setInputFile() or setInputString() if you
+     * pass a string
+     *
+     * @param mixed $fp Can be either a resource returned from fopen(),
+     *                  a URL, a local filename or a string.
+     *
+     * @return mixed
+     * @access public
+     * @see parse()
+     * @uses setInputString(), setInputFile()
+     */
+    function setInput($fp)
+    {
+        if (is_resource($fp)) {
+            $this->fp = $fp;
+            return true;
+        } elseif (preg_match('/^[a-z]+:\/\//i', substr($fp, 0, 10))) {
+            // see if it's an absolute URL (has a scheme at the beginning)
+            return $this->setInputFile($fp);
+        } elseif (file_exists($fp)) {
+            // see if it's a local file
+            return $this->setInputFile($fp);
+        } else {
+            // it must be a string
+            $this->fp = $fp;
+            return true;
+        }
+
+        return $this->raiseError('Illegal input format', 
+            XML_PARSER_ERROR_INVALID_INPUT);
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * Central parsing function.
+     *
+     * @return bool|PEAR_Error returns true on success, or a PEAR_Error otherwise
+     * @access public
+     */
+    function parse()
+    {
+        /**
+         * reset the parser
+         */
+        $result = $this->reset();
+        if ($this->isError($result)) {
+            return $result;
+        }
+        // if $this->fp was fopened previously
+        if (is_resource($this->fp)) {
+
+            while ($data = fread($this->fp, 4096)) {
+                if (!$this->_parseString($data, feof($this->fp))) {
+                    $error = &$this->raiseError();
+                    $this->free();
+                    return $error;
+                }
+            }
+        } else {
+            // otherwise, $this->fp must be a string
+            if (!$this->_parseString($this->fp, true)) {
+                $error = &$this->raiseError();
+                $this->free();
+                return $error;
+            }
+        }
+        $this->free();
+
+        return true;
+    }
+
+    /**
+     * XML_Parser::_parseString()
+     *
+     * @param string $data data
+     * @param bool   $eof  end-of-file flag
+     *
+     * @return bool
+     * @access private
+     * @see parseString()
+     **/
+    function _parseString($data, $eof = false)
+    {
+        return xml_parse($this->parser, $data, $eof);
+    }
+
+    // }}}
+    // {{{ parseString()
+
+    /**
+     * XML_Parser::parseString()
+     *
+     * Parses a string.
+     *
+     * @param string  $data XML data
+     * @param boolean $eof  If set and TRUE, data is the last piece 
+     *                      of data sent in this parser
+     *
+     * @return bool|PEAR_Error true on success or a PEAR Error
+     * @throws XML_Parser_Error
+     * @see _parseString()
+     */
+    function parseString($data, $eof = false)
+    {
+        if (!isset($this->parser) || !is_resource($this->parser)) {
+            $this->reset();
+        }
+
+        if (!$this->_parseString($data, $eof)) {
+            $error = &$this->raiseError();
+            $this->free();
+            return $error;
+        }
+
+        if ($eof === true) {
+            $this->free();
+        }
+        return true;
+    }
+
+    /**
+     * XML_Parser::free()
+     *
+     * Free the internal resources associated with the parser
+     *
+     * @return null
+     **/
+    function free()
+    {
+        if (isset($this->parser) && is_resource($this->parser)) {
+            xml_parser_free($this->parser);
+            unset( $this->parser );
+        }
+        if (isset($this->fp) && is_resource($this->fp)) {
+            fclose($this->fp);
+        }
+        unset($this->fp);
+        return null;
+    }
+
+    /**
+     * XML_Parser::raiseError()
+     *
+     * Throws a XML_Parser_Error
+     *
+     * @param string  $msg   the error message
+     * @param integer $ecode the error message code
+     *
+     * @return XML_Parser_Error reference to the error object
+     **/
+    function &raiseError($msg = null, $ecode = 0)
+    {
+        $msg = !is_null($msg) ? $msg : $this->parser;
+        $err = &new XML_Parser_Error($msg, $ecode);
+        return parent::raiseError($err);
+    }
+
+    // }}}
+    // {{{ funcStartHandler()
+
+    /**
+     * derives and calls the Start Handler function
+     *
+     * @param mixed $xp      ??
+     * @param mixed $elem    ??
+     * @param mixed $attribs ??
+     *
+     * @return void
+     */
+    function funcStartHandler($xp, $elem, $attribs)
+    {
+        $func = 'xmltag_' . $elem;
+        $func = str_replace(array('.', '-', ':'), '_', $func);
+        if (method_exists($this->_handlerObj, $func)) {
+            call_user_func(array(&$this->_handlerObj, $func), $xp, $elem, $attribs);
+        } elseif (method_exists($this->_handlerObj, 'xmltag')) {
+            call_user_func(array(&$this->_handlerObj, 'xmltag'), 
+                $xp, $elem, $attribs);
+        }
+    }
+
+    // }}}
+    // {{{ funcEndHandler()
+
+    /**
+     * derives and calls the End Handler function
+     *
+     * @param mixed $xp   ??
+     * @param mixed $elem ??
+     *
+     * @return void
+     */
+    function funcEndHandler($xp, $elem)
+    {
+        $func = 'xmltag_' . $elem . '_';
+        $func = str_replace(array('.', '-', ':'), '_', $func);
+        if (method_exists($this->_handlerObj, $func)) {
+            call_user_func(array(&$this->_handlerObj, $func), $xp, $elem);
+        } elseif (method_exists($this->_handlerObj, 'xmltag_')) {
+            call_user_func(array(&$this->_handlerObj, 'xmltag_'), $xp, $elem);
+        }
+    }
+
+    // }}}
+    // {{{ startHandler()
+
+    /**
+     * abstract method signature for Start Handler
+     *
+     * @param mixed $xp       ??
+     * @param mixed $elem     ??
+     * @param mixed &$attribs ??
+     *
+     * @return null
+     * @abstract
+     */
+    function startHandler($xp, $elem, &$attribs)
+    {
+        return null;
+    }
+
+    // }}}
+    // {{{ endHandler()
+
+    /**
+     * abstract method signature for End Handler
+     *
+     * @param mixed $xp   ??
+     * @param mixed $elem ??
+     *
+     * @return null
+     * @abstract
+     */
+    function endHandler($xp, $elem)
+    {
+        return null;
+    }
+
+
+    // }}}me
+}
+
+/**
+ * error class, replaces PEAR_Error
+ *
+ * An instance of this class will be returned
+ * if an error occurs inside XML_Parser.
+ *
+ * There are three advantages over using the standard PEAR_Error:
+ * - All messages will be prefixed
+ * - check for XML_Parser error, using is_a( $error, 'XML_Parser_Error' )
+ * - messages can be generated from the xml_parser resource
+ *
+ * @category  XML
+ * @package   XML_Parser
+ * @author    Stig Bakken <ssb@fast.no>
+ * @author    Tomas V.V.Cox <cox@idecnet.com>
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2002-2008 The PHP Group
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/XML_Parser
+ * @see       PEAR_Error
+ */
+class XML_Parser_Error extends PEAR_Error
+{
+    // {{{ properties
+
+    /**
+    * prefix for all messages
+    *
+    * @var      string
+    */
+    var $error_message_prefix = 'XML_Parser: ';
+
+    // }}}
+    // {{{ constructor()
+    /**
+    * construct a new error instance
+    *
+    * You may either pass a message or an xml_parser resource as first
+    * parameter. If a resource has been passed, the last error that
+    * happened will be retrieved and returned.
+    *
+    * @param string|resource $msgorparser message or parser resource
+    * @param integer         $code        error code
+    * @param integer         $mode        error handling
+    * @param integer         $level       error level
+    *
+    * @access   public
+    * @todo PEAR CS - can't meet 85char line limit without arg refactoring
+    */
+    function XML_Parser_Error($msgorparser = 'unknown error', $code = 0, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE)
+    {
+        if (is_resource($msgorparser)) {
+            $code        = xml_get_error_code($msgorparser);
+            $msgorparser = sprintf('%s at XML input line %d:%d',
+                xml_error_string($code),
+                xml_get_current_line_number($msgorparser),
+                xml_get_current_column_number($msgorparser));
+        }
+        $this->PEAR_Error($msgorparser, $code, $mode, $level);
+    }
+    // }}}
+}
+?>
Index: branches/version-2_12-dev/data/module/XML/Unserializer.php
===================================================================
--- branches/version-2_12-dev/data/module/XML/Unserializer.php	(revision 21713)
+++ branches/version-2_12-dev/data/module/XML/Unserializer.php	(revision 21713)
@@ -0,0 +1,983 @@
+<?PHP
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Unserializer
+ *
+ * Parses any XML document into PHP data structures.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * The name of the author may not be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  XML
+ * @package   XML_Serializer
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   CVS: $Id: Unserializer.php 303099 2010-09-06 16:23:06Z clockwerx $
+ * @link      http://pear.php.net/package/XML_Serializer
+ * @see       XML_Unserializer
+ */
+
+/**
+ * uses PEAR error managemt
+ */
+require_once 'PEAR.php';
+
+/**
+ * uses XML_Parser to unserialize document
+ */
+require_once 'XML/Parser.php';
+
+/**
+ * option: Convert nested tags to array or object
+ *
+ * Possible values:
+ * - array
+ * - object
+ * - associative array to define this option per tag name
+ */
+define('XML_UNSERIALIZER_OPTION_COMPLEXTYPE', 'complexType');
+
+/**
+ * option: Name of the attribute that stores the original key
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
+
+/**
+ * option: Name of the attribute that stores the type
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
+
+/**
+ * option: Name of the attribute that stores the class name
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
+
+/**
+ * option: Whether to use the tag name as a class name
+ *
+ * Possible values:
+ * - true or false
+ */
+define('XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME', 'tagAsClass');
+
+/**
+ * option: Name of the default class
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_DEFAULT_CLASS', 'defaultClass');
+
+/**
+ * option: Whether to parse attributes
+ *
+ * Possible values:
+ * - true or false
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE', 'parseAttributes');
+
+/**
+ * option: Key of the array to store attributes (if any)
+ *
+ * Possible values:
+ * - any string
+ * - false (disabled)
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY', 'attributesArray');
+
+/**
+ * option: string to prepend attribute name (if any)
+ *
+ * Possible values:
+ * - any string
+ * - false (disabled)
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND', 'prependAttributes');
+
+/**
+ * option: key to store the content,
+ * if XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE is used
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_CONTENT_KEY', 'contentName');
+
+/**
+ * option: map tag names
+ *
+ * Possible values:
+ * - associative array
+ */
+define('XML_UNSERIALIZER_OPTION_TAG_MAP', 'tagMap');
+
+/**
+ * option: list of tags that will always be enumerated
+ *
+ * Possible values:
+ * - indexed array
+ */
+define('XML_UNSERIALIZER_OPTION_FORCE_ENUM', 'forceEnum');
+
+/**
+ * option: Encoding of the XML document
+ *
+ * Possible values:
+ * - UTF-8
+ * - ISO-8859-1
+ */
+define('XML_UNSERIALIZER_OPTION_ENCODING_SOURCE', 'encoding');
+
+/**
+ * option: Desired target encoding of the data
+ *
+ * Possible values:
+ * - UTF-8
+ * - ISO-8859-1
+ */
+define('XML_UNSERIALIZER_OPTION_ENCODING_TARGET', 'targetEncoding');
+
+/**
+ * option: Callback that will be applied to textual data
+ *
+ * Possible values:
+ * - any valid PHP callback
+ */
+define('XML_UNSERIALIZER_OPTION_DECODE_FUNC', 'decodeFunction');
+
+/**
+ * option: whether to return the result of the unserialization from unserialize()
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_UNSERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
+
+/**
+ * option: set the whitespace behaviour
+ *
+ * Possible values:
+ * - XML_UNSERIALIZER_WHITESPACE_KEEP
+ * - XML_UNSERIALIZER_WHITESPACE_TRIM
+ * - XML_UNSERIALIZER_WHITESPACE_NORMALIZE
+ */
+define('XML_UNSERIALIZER_OPTION_WHITESPACE', 'whitespace');
+
+/**
+ * Keep all whitespace
+ */
+define('XML_UNSERIALIZER_WHITESPACE_KEEP', 'keep');
+
+/**
+ * remove whitespace from start and end of the data
+ */
+define('XML_UNSERIALIZER_WHITESPACE_TRIM', 'trim');
+
+/**
+ * normalize whitespace
+ */
+define('XML_UNSERIALIZER_WHITESPACE_NORMALIZE', 'normalize');
+
+/**
+ * option: whether to ovverride all options that have been set before
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS', 'overrideOptions');
+
+/**
+ * option: list of tags, that will not be used as keys
+ */
+define('XML_UNSERIALIZER_OPTION_IGNORE_KEYS', 'ignoreKeys');
+
+/**
+ * option: whether to use type guessing for scalar values
+ */
+define('XML_UNSERIALIZER_OPTION_GUESS_TYPES', 'guessTypes');
+
+/**
+ * error code for no serialization done
+ */
+define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION', 151);
+
+/**
+ * XML_Unserializer
+ *
+ * class to unserialize XML documents that have been created with
+ * XML_Serializer. To unserialize an XML document you have to add
+ * type hints to the XML_Serializer options.
+ *
+ * If no type hints are available, XML_Unserializer will guess how
+ * the tags should be treated, that means complex structures will be
+ * arrays and tags with only CData in them will be strings.
+ *
+ * <code>
+ * require_once 'XML/Unserializer.php';
+ *
+ * //  be careful to always use the ampersand in front of the new operator
+ * $unserializer = &new XML_Unserializer();
+ *
+ * $unserializer->unserialize($xml);
+ *
+ * $data = $unserializer->getUnserializedData();
+ * </code>
+ *
+ * @category  XML
+ * @package   XML_Serializer
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/XML_Serializer
+ * @see       XML_Serializer
+ */
+class XML_Unserializer extends PEAR
+{
+    /**
+     * list of all available options
+     *
+     * @access private
+     * @var    array
+     */
+    var $_knownOptions = array(
+                                XML_UNSERIALIZER_OPTION_COMPLEXTYPE,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS,
+                                XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME,
+                                XML_UNSERIALIZER_OPTION_DEFAULT_CLASS,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY,
+                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND,
+                                XML_UNSERIALIZER_OPTION_CONTENT_KEY,
+                                XML_UNSERIALIZER_OPTION_TAG_MAP,
+                                XML_UNSERIALIZER_OPTION_FORCE_ENUM,
+                                XML_UNSERIALIZER_OPTION_ENCODING_SOURCE,
+                                XML_UNSERIALIZER_OPTION_ENCODING_TARGET,
+                                XML_UNSERIALIZER_OPTION_DECODE_FUNC,
+                                XML_UNSERIALIZER_OPTION_RETURN_RESULT,
+                                XML_UNSERIALIZER_OPTION_WHITESPACE,
+                                XML_UNSERIALIZER_OPTION_IGNORE_KEYS,
+                                XML_UNSERIALIZER_OPTION_GUESS_TYPES
+                              );
+    /**
+     * default options for the serialization
+     *
+     * @access private
+     * @var    array
+     */
+    var $_defaultOptions = array(
+        // complex types will be converted to arrays, if no type hint is given
+        XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array',
+
+        // get array key/property name from this attribute
+        XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey',
+
+        // get type from this attribute
+        XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type',
+
+        // get class from this attribute (if not given, use tag name)
+        XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class',
+
+        // use the tagname as the classname
+        XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME => true,
+
+        // name of the class that is used to create objects
+        XML_UNSERIALIZER_OPTION_DEFAULT_CLASS => 'stdClass',
+
+        // parse the attributes of the tag into an array
+        XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => false,
+
+        // parse them into sperate array (specify name of array here)
+        XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => false,
+
+        // prepend attribute names with this string
+        XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND => '',
+
+        // put cdata found in a tag that has been converted
+        // to a complex type in this key
+        XML_UNSERIALIZER_OPTION_CONTENT_KEY => '_content',
+
+        // use this to map tagnames
+        XML_UNSERIALIZER_OPTION_TAG_MAP => array(),
+
+        // these tags will always be an indexed array
+        XML_UNSERIALIZER_OPTION_FORCE_ENUM => array(),
+
+        // specify the encoding character of the document to parse
+        XML_UNSERIALIZER_OPTION_ENCODING_SOURCE => null,
+
+        // specify the target encoding
+        XML_UNSERIALIZER_OPTION_ENCODING_TARGET => null,
+
+        // function used to decode data
+        XML_UNSERIALIZER_OPTION_DECODE_FUNC => null,
+
+        // unserialize() returns the result of the unserialization instead of true
+        XML_UNSERIALIZER_OPTION_RETURN_RESULT => false,
+
+        // remove whitespace around data
+        XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_TRIM,
+
+        // List of tags that will automatically be added to the parent,
+        // instead of adding a new key
+        XML_UNSERIALIZER_OPTION_IGNORE_KEYS => array(),
+
+        // Whether to use type guessing
+        XML_UNSERIALIZER_OPTION_GUESS_TYPES => false
+    );
+
+    /**
+     * current options for the serialization
+     *
+     * @access public
+     * @var    array
+     */
+    var $options = array();
+
+    /**
+     * unserialized data
+     *
+     * @access private
+     * @var    string
+     */
+    var $_unserializedData = null;
+
+    /**
+     * name of the root tag
+     *
+     * @access private
+     * @var    string
+     */
+    var $_root = null;
+
+    /**
+     * stack for all data that is found
+     *
+     * @access private
+     * @var    array
+     */
+    var $_dataStack = array();
+
+    /**
+     * stack for all values that are generated
+     *
+     * @access private
+     * @var    array
+     */
+    var $_valStack = array();
+
+    /**
+     * current tag depth
+     *
+     * @access private
+     * @var    int
+     */
+    var $_depth = 0;
+
+    /**
+     * XML_Parser instance
+     *
+     * @access   private
+     * @var      object XML_Parser
+     */
+    var $_parser = null;
+
+    /**
+     * constructor
+     *
+     * @param mixed $options array containing options for the unserialization
+     *
+     * @access public
+     */
+    function XML_Unserializer($options = null)
+    {
+        if (is_array($options)) {
+            $this->options = array_merge($this->_defaultOptions, $options);
+        } else {
+            $this->options = $this->_defaultOptions;
+        }
+    }
+
+    /**
+     * return API version
+     *
+     * @access   public
+     * @return string  $version API version
+     * @static
+     */
+    function apiVersion()
+    {
+        return '@package_version@';
+    }
+
+    /**
+     * reset all options to default options
+     *
+     * @return void
+     * @access public
+     * @see setOption(), XML_Unserializer(), setOptions()
+     */
+    function resetOptions()
+    {
+        $this->options = $this->_defaultOptions;
+    }
+
+    /**
+     * set an option
+     *
+     * You can use this method if you do not want
+     * to set all options in the constructor
+     *
+     * @param string $name  name of option
+     * @param mixed  $value value of option
+     *
+     * @return void
+     * @access public
+     * @see resetOption(), XML_Unserializer(), setOptions()
+     */
+    function setOption($name, $value)
+    {
+        $this->options[$name] = $value;
+    }
+
+    /**
+     * sets several options at once
+     *
+     * You can use this method if you do not want
+     * to set all options in the constructor
+     *
+     * @param array $options options array
+     *
+     * @return void
+     * @access public
+     * @see resetOption(), XML_Unserializer(), setOption()
+     */
+    function setOptions($options)
+    {
+        $this->options = array_merge($this->options, $options);
+    }
+
+    /**
+     * unserialize data
+     *
+     * @param mixed   $data    data to unserialize (string, filename or resource)
+     * @param boolean $isFile  data should be treated as a file
+     * @param array   $options options that will override
+     *                         the global options for this call
+     *
+     * @return boolean $success
+     * @access public
+     */
+    function unserialize($data, $isFile = false, $options = null)
+    {
+        $this->_unserializedData = null;
+        $this->_root             = null;
+
+        // if options have been specified, use them instead
+        // of the previously defined ones
+        if (is_array($options)) {
+            $optionsBak = $this->options;
+            if (isset($options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS])
+                && $options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS] == true
+            ) {
+                $this->options = array_merge($this->_defaultOptions, $options);
+            } else {
+                $this->options = array_merge($this->options, $options);
+            }
+        } else {
+            $optionsBak = null;
+        }
+
+        $this->_valStack  = array();
+        $this->_dataStack = array();
+        $this->_depth     = 0;
+
+        $this->_createParser();
+
+        if (is_string($data)) {
+            if ($isFile) {
+                $result = $this->_parser->setInputFile($data);
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+                $result = $this->_parser->parse();
+            } else {
+                $result = $this->_parser->parseString($data, true);
+            }
+        } else {
+            $this->_parser->setInput($data);
+            $result = $this->_parser->parse();
+        }
+
+        if ($this->options[XML_UNSERIALIZER_OPTION_RETURN_RESULT] === true) {
+            $return = $this->_unserializedData;
+        } else {
+            $return = true;
+        }
+
+        if ($optionsBak !== null) {
+            $this->options = $optionsBak;
+        }
+
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        return $return;
+    }
+
+    /**
+     * get the result of the serialization
+     *
+     * @access public
+     * @return string  $serializedData
+     */
+    function getUnserializedData()
+    {
+        if ($this->_root === null) {
+            return $this->raiseError('No unserialized data available. '
+                . 'Use XML_Unserializer::unserialize() first.',
+                XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
+        }
+        return $this->_unserializedData;
+    }
+
+    /**
+     * get the name of the root tag
+     *
+     * @access public
+     * @return string  $rootName
+     */
+    function getRootName()
+    {
+        if ($this->_root === null) {
+            return $this->raiseError('No unserialized data available. '
+                . 'Use XML_Unserializer::unserialize() first.',
+                XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
+        }
+        return $this->_root;
+    }
+
+    /**
+     * Start element handler for XML parser
+     *
+     * @param object $parser  XML parser object
+     * @param string $element XML element
+     * @param array  $attribs attributes of XML tag
+     *
+     * @return void
+     * @access private
+     */
+    function startHandler($parser, $element, $attribs)
+    {
+        if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]])
+        ) {
+            $type = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]];
+
+            $guessType = false;
+        } else {
+            $type = 'string';
+            if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
+                $guessType = true;
+            } else {
+                $guessType = false;
+            }
+        }
+
+        if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
+            $attribs = array_map($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC],
+                $attribs);
+        }
+
+        $this->_depth++;
+        $this->_dataStack[$this->_depth] = null;
+
+        if (is_array($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP])
+            && isset($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element])
+        ) {
+            $element = $this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element];
+        }
+
+        $val = array(
+                     'name'         => $element,
+                     'value'        => null,
+                     'type'         => $type,
+                     'guessType'    => $guessType,
+                     'childrenKeys' => array(),
+                     'aggregKeys'   => array()
+                    );
+
+        if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE] == true
+            && (count($attribs) > 0)
+        ) {
+            $val['children'] = array();
+            $val['type']     = $this->_getComplexType($element);
+            $val['class']    = $element;
+
+            if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
+                $attribs = $this->_guessAndSetTypes($attribs);
+            }
+            if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY] != false
+            ) {
+                $val['children'][$this->
+                    options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY]] = $attribs;
+            } else {
+                foreach ($attribs as $attrib => $value) {
+                    $val['children'][$this->
+                        options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND]
+                        . $attrib] = $value;
+                }
+            }
+        }
+
+        $keyAttr = false;
+
+        if (is_string($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
+            $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY];
+        } elseif (is_array($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
+            if (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
+                [$element])
+            ) {
+                $keyAttr =
+                    $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element];
+            } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
+                ['#default'])
+            ) {
+                $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
+                ['#default'];
+            } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
+                ['__default'])
+            ) {
+                // keep this for BC
+                $keyAttr =
+                    $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
+                    ['__default'];
+            }
+        }
+
+        if ($keyAttr !== false && isset($attribs[$keyAttr])) {
+            $val['name'] = $attribs[$keyAttr];
+        }
+
+        if (isset($attribs[$this->
+            options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]])
+        ) {
+            $val['class'] =
+                $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]];
+        }
+
+        array_push($this->_valStack, $val);
+    }
+
+    /**
+     * Try to guess the type of several values and
+     * set them accordingly
+     *
+     * @param array $array array containing the values
+     *
+     * @return array array, containing the values with their correct types
+     * @access private
+     */
+    function _guessAndSetTypes($array)
+    {
+        foreach ($array as $key => $value) {
+            $array[$key] = $this->_guessAndSetType($value);
+        }
+        return $array;
+    }
+
+    /**
+     * Try to guess the type of a value and
+     * set it accordingly
+     *
+     * @param string $value character data
+     *
+     * @return mixed value with the best matching type
+     * @access private
+     */
+    function _guessAndSetType($value)
+    {
+        if ($value === 'true') {
+            return true;
+        }
+        if ($value === 'false') {
+            return false;
+        }
+        if ($value === 'NULL') {
+            return null;
+        }
+        if (preg_match('/^[-+]?[0-9]{1,}\\z/', $value)) {
+            return intval($value);
+        }
+        if (preg_match('/^[-+]?[0-9]{1,}\.[0-9]{1,}\\z/', $value)) {
+            return doubleval($value);
+        }
+        return (string)$value;
+    }
+
+    /**
+     * End element handler for XML parser
+     *
+     * @param object $parser  XML parser object
+     * @param string $element element
+     *
+     * @return void
+     * @access private
+     */
+    function endHandler($parser, $element)
+    {
+        $value = array_pop($this->_valStack);
+        switch ($this->options[XML_UNSERIALIZER_OPTION_WHITESPACE]) {
+        case XML_UNSERIALIZER_WHITESPACE_KEEP:
+            $data = $this->_dataStack[$this->_depth];
+            break;
+        case XML_UNSERIALIZER_WHITESPACE_NORMALIZE:
+            $data = trim(preg_replace('/\s\s+/m', ' ',
+                $this->_dataStack[$this->_depth]));
+            break;
+        case XML_UNSERIALIZER_WHITESPACE_TRIM:
+        default:
+            $data = trim($this->_dataStack[$this->_depth]);
+            break;
+        }
+
+        // adjust type of the value
+        switch(strtolower($value['type'])) {
+
+        // unserialize an object
+        case 'object':
+            if (isset($value['class'])) {
+                $classname = $value['class'];
+            } else {
+                $classname = '';
+            }
+            // instantiate the class
+            if ($this->options[XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME] === true
+                && class_exists($classname)
+            ) {
+                $value['value'] = new $classname;
+            } else {
+                $value['value'] =
+                    new $this->options[XML_UNSERIALIZER_OPTION_DEFAULT_CLASS];
+            }
+            if (trim($data) !== '') {
+                if ($value['guessType'] === true) {
+                    $data = $this->_guessAndSetType($data);
+                }
+                $value['children'][$this->
+                    options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
+            }
+
+            // set properties
+            foreach ($value['children'] as $prop => $propVal) {
+                // check whether there is a special method to set this property
+                $setMethod = 'set'.$prop;
+                if (method_exists($value['value'], $setMethod)) {
+                    call_user_func(array(&$value['value'], $setMethod), $propVal);
+                } else {
+                    $value['value']->$prop = $propVal;
+                }
+            }
+            //  check for magic function
+            if (method_exists($value['value'], '__wakeup')) {
+                $value['value']->__wakeup();
+            }
+            break;
+
+        // unserialize an array
+        case 'array':
+            if (trim($data) !== '') {
+                if ($value['guessType'] === true) {
+                    $data = $this->_guessAndSetType($data);
+                }
+                $value['children'][$this->
+                    options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
+            }
+            if (isset($value['children'])) {
+                $value['value'] = $value['children'];
+            } else {
+                $value['value'] = array();
+            }
+            break;
+
+        // unserialize a null value
+        case 'null':
+            $data = null;
+            break;
+
+        // unserialize a resource => this is not possible :-(
+        case 'resource':
+            $value['value'] = $data;
+            break;
+
+        // unserialize any scalar value
+        default:
+            if ($value['guessType'] === true) {
+                $data = $this->_guessAndSetType($data);
+            } else {
+                settype($data, $value['type']);
+            }
+
+            $value['value'] = $data;
+            break;
+        }
+        $parent = array_pop($this->_valStack);
+        if ($parent === null) {
+            $this->_unserializedData = &$value['value'];
+            $this->_root             = &$value['name'];
+            return true;
+        } else {
+            // parent has to be an array
+            if (!isset($parent['children']) || !is_array($parent['children'])) {
+                $parent['children'] = array();
+                if (!in_array($parent['type'], array('array', 'object'))) {
+                    $parent['type'] = $this->_getComplexType($parent['name']);
+                    if ($parent['type'] == 'object') {
+                        $parent['class'] = $parent['name'];
+                    }
+                }
+            }
+
+            if (in_array($element,
+                $this->options[XML_UNSERIALIZER_OPTION_IGNORE_KEYS])
+            ) {
+                $ignoreKey = true;
+            } else {
+                $ignoreKey = false;
+            }
+
+            if (!empty($value['name']) && $ignoreKey === false) {
+                // there already has been a tag with this name
+                if (in_array($value['name'], $parent['childrenKeys'])
+                    || in_array($value['name'],
+                    $this->options[XML_UNSERIALIZER_OPTION_FORCE_ENUM])
+                ) {
+                    // no aggregate has been created for this tag
+                    if (!in_array($value['name'], $parent['aggregKeys'])) {
+                        if (isset($parent['children'][$value['name']])) {
+                            $parent['children'][$value['name']] =
+                                array($parent['children'][$value['name']]);
+                        } else {
+                            $parent['children'][$value['name']] = array();
+                        }
+                        array_push($parent['aggregKeys'], $value['name']);
+                    }
+                    array_push($parent['children'][$value['name']], $value['value']);
+                } else {
+                    $parent['children'][$value['name']] = &$value['value'];
+                    array_push($parent['childrenKeys'], $value['name']);
+                }
+            } else {
+                array_push($parent['children'], $value['value']);
+            }
+            array_push($this->_valStack, $parent);
+        }
+
+        $this->_depth--;
+    }
+
+    /**
+     * Handler for character data
+     *
+     * @param object $parser XML parser object
+     * @param string $cdata  CDATA
+     *
+     * @return void
+     * @access private
+     */
+    function cdataHandler($parser, $cdata)
+    {
+        if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
+            $cdata = call_user_func($this->
+                options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $cdata);
+        }
+        $this->_dataStack[$this->_depth] .= $cdata;
+    }
+
+    /**
+     * get the complex type, that should be used for a specified tag
+     *
+     * @param string $tagname name of the tag
+     *
+     * @return string complex type ('array' or 'object')
+     * @access private
+     */
+    function _getComplexType($tagname)
+    {
+        if (is_string($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE])) {
+            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE];
+        }
+        if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname])) {
+            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname];
+        }
+        if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'])) {
+            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'];
+        }
+        return 'array';
+    }
+
+    /**
+     * create the XML_Parser instance
+     *
+     * @return boolean
+     * @access private
+     */
+    function _createParser()
+    {
+        if (is_object($this->_parser)) {
+            $this->_parser->free();
+            unset($this->_parser);
+        }
+        $this->_parser = new XML_Parser($this->
+            options[XML_UNSERIALIZER_OPTION_ENCODING_SOURCE],
+            'event', $this->options[XML_UNSERIALIZER_OPTION_ENCODING_TARGET]);
+
+        $this->_parser->folding = false;
+        $this->_parser->setHandlerObj($this);
+        return true;
+    }
+}
+?>
Index: branches/version-2_12-dev/data/module/XML/Util.php
===================================================================
--- branches/version-2_12-dev/data/module/XML/Util.php	(revision 21713)
+++ branches/version-2_12-dev/data/module/XML/Util.php	(revision 21713)
@@ -0,0 +1,911 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Util
+ *
+ * XML Utilities package
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * The name of the author may not be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  XML
+ * @package   XML_Util
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   CVS: $Id: Util.php,v 1.38 2008/11/13 00:03:38 ashnazg Exp $
+ * @link      http://pear.php.net/package/XML_Util
+ */
+
+/**
+ * error code for invalid chars in XML name
+ */
+define('XML_UTIL_ERROR_INVALID_CHARS', 51);
+
+/**
+ * error code for invalid chars in XML name
+ */
+define('XML_UTIL_ERROR_INVALID_START', 52);
+
+/**
+ * error code for non-scalar tag content
+ */
+define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60);
+
+/**
+ * error code for missing tag name
+ */
+define('XML_UTIL_ERROR_NO_TAG_NAME', 61);
+
+/**
+ * replace XML entities
+ */
+define('XML_UTIL_REPLACE_ENTITIES', 1);
+
+/**
+ * embedd content in a CData Section
+ */
+define('XML_UTIL_CDATA_SECTION', 5);
+
+/**
+ * do not replace entitites
+ */
+define('XML_UTIL_ENTITIES_NONE', 0);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define('XML_UTIL_ENTITIES_XML', 1);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define('XML_UTIL_ENTITIES_XML_REQUIRED', 2);
+
+/**
+ * replace HTML entitites
+ * @link http://www.php.net/htmlentities
+ */
+define('XML_UTIL_ENTITIES_HTML', 3);
+
+/**
+ * Collapse all empty tags.
+ */
+define('XML_UTIL_COLLAPSE_ALL', 1);
+
+/**
+ * Collapse only empty XHTML tags that have no end tag.
+ */
+define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2);
+
+/**
+ * utility class for working with XML documents
+ *
+
+ * @category  XML
+ * @package   XML_Util
+ * @author    Stephan Schmidt <schst@php.net>
+ * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
+ * @license   http://opensource.org/licenses/bsd-license New BSD License
+ * @version   Release: 1.2.1
+ * @link      http://pear.php.net/package/XML_Util
+ */
+class XML_Util
+{
+    /**
+     * return API version
+     *
+     * @return string $version API version
+     * @access public
+     * @static
+     */
+    function apiVersion()
+    {
+        return '1.1';
+    }
+
+    /**
+     * replace XML entities
+     *
+     * With the optional second parameter, you may select, which
+     * entities should be replaced.
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // replace XML entites:
+     * $string = XML_Util::replaceEntities('This string contains < & >.');
+     * </code>
+     *
+     * With the optional third parameter, you may pass the character encoding
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // replace XML entites in UTF-8:
+     * $string = XML_Util::replaceEntities(
+     *     'This string contains < & > as well as ä, ö, ß, à and ê',
+     *     XML_UTIL_ENTITIES_HTML,
+     *     'UTF-8'
+     * );
+     * </code>
+     *
+     * @param string $string          string where XML special chars 
+     *                                should be replaced
+     * @param int    $replaceEntities setting for entities in attribute values 
+     *                                (one of XML_UTIL_ENTITIES_XML, 
+     *                                XML_UTIL_ENTITIES_XML_REQUIRED, 
+     *                                XML_UTIL_ENTITIES_HTML)
+     * @param string $encoding        encoding value (if any)...
+     *                                must be a valid encoding as determined
+     *                                by the htmlentities() function
+     *
+     * @return string string with replaced chars
+     * @access public
+     * @static
+     * @see reverseEntities()
+     */
+    function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML,
+        $encoding = 'ISO-8859-1')
+    {
+        switch ($replaceEntities) {
+        case XML_UTIL_ENTITIES_XML:
+            return strtr($string, array(
+                '&'  => '&amp;',
+                '>'  => '&gt;',
+                '<'  => '&lt;',
+                '"'  => '&quot;',
+                '\'' => '&apos;' ));
+            break;
+        case XML_UTIL_ENTITIES_XML_REQUIRED:
+            return strtr($string, array(
+                '&' => '&amp;',
+                '<' => '&lt;',
+                '"' => '&quot;' ));
+            break;
+        case XML_UTIL_ENTITIES_HTML:
+            return htmlentities($string, ENT_COMPAT, $encoding);
+            break;
+        }
+        return $string;
+    }
+
+    /**
+     * reverse XML entities
+     *
+     * With the optional second parameter, you may select, which
+     * entities should be reversed.
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // reverse XML entites:
+     * $string = XML_Util::reverseEntities('This string contains &lt; &amp; &gt;.');
+     * </code>
+     *
+     * With the optional third parameter, you may pass the character encoding
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // reverse XML entites in UTF-8:
+     * $string = XML_Util::reverseEntities(
+     *     'This string contains &lt; &amp; &gt; as well as'
+     *     . ' &auml;, &ouml;, &szlig;, &agrave; and &ecirc;',
+     *     XML_UTIL_ENTITIES_HTML,
+     *     'UTF-8'
+     * );
+     * </code>
+     *
+     * @param string $string          string where XML special chars 
+     *                                should be replaced
+     * @param int    $replaceEntities setting for entities in attribute values 
+     *                                (one of XML_UTIL_ENTITIES_XML, 
+     *                                XML_UTIL_ENTITIES_XML_REQUIRED, 
+     *                                XML_UTIL_ENTITIES_HTML)
+     * @param string $encoding        encoding value (if any)...
+     *                                must be a valid encoding as determined
+     *                                by the html_entity_decode() function
+     *
+     * @return string string with replaced chars
+     * @access public
+     * @static
+     * @see replaceEntities()
+     */
+    function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML,
+        $encoding = 'ISO-8859-1')
+    {
+        switch ($replaceEntities) {
+        case XML_UTIL_ENTITIES_XML:
+            return strtr($string, array(
+                '&amp;'  => '&',
+                '&gt;'   => '>',
+                '&lt;'   => '<',
+                '&quot;' => '"',
+                '&apos;' => '\'' ));
+            break;
+        case XML_UTIL_ENTITIES_XML_REQUIRED:
+            return strtr($string, array(
+                '&amp;'  => '&',
+                '&lt;'   => '<',
+                '&quot;' => '"' ));
+            break;
+        case XML_UTIL_ENTITIES_HTML:
+            return html_entity_decode($string, ENT_COMPAT, $encoding);
+            break;
+        }
+        return $string;
+    }
+
+    /**
+     * build an xml declaration
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // get an XML declaration:
+     * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true);
+     * </code>
+     *
+     * @param string $version    xml version
+     * @param string $encoding   character encoding
+     * @param bool   $standalone document is standalone (or not)
+     *
+     * @return string xml declaration
+     * @access public
+     * @static
+     * @uses attributesToString() to serialize the attributes of the XML declaration
+     */
+    function getXMLDeclaration($version = '1.0', $encoding = null, 
+        $standalone = null)
+    {
+        $attributes = array(
+            'version' => $version,
+        );
+        // add encoding
+        if ($encoding !== null) {
+            $attributes['encoding'] = $encoding;
+        }
+        // add standalone, if specified
+        if ($standalone !== null) {
+            $attributes['standalone'] = $standalone ? 'yes' : 'no';
+        }
+
+        return sprintf('<?xml%s?>', 
+            XML_Util::attributesToString($attributes, false));
+    }
+
+    /**
+     * build a document type declaration
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // get a doctype declaration:
+     * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd');
+     * </code>
+     *
+     * @param string $root        name of the root tag
+     * @param string $uri         uri of the doctype definition 
+     *                            (or array with uri and public id)
+     * @param string $internalDtd internal dtd entries
+     *
+     * @return string doctype declaration
+     * @access public
+     * @static
+     * @since 0.2
+     */
+    function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
+    {
+        if (is_array($uri)) {
+            $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']);
+        } elseif (!empty($uri)) {
+            $ref = sprintf(' SYSTEM "%s"', $uri);
+        } else {
+            $ref = '';
+        }
+
+        if (empty($internalDtd)) {
+            return sprintf('<!DOCTYPE %s%s>', $root, $ref);
+        } else {
+            return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
+        }
+    }
+
+    /**
+     * create string representation of an attribute list
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // build an attribute string
+     * $att = array(
+     *              'foo'   =>  'bar',
+     *              'argh'  =>  'tomato'
+     *            );
+     *
+     * $attList = XML_Util::attributesToString($att);
+     * </code>
+     *
+     * @param array      $attributes attribute array
+     * @param bool|array $sort       sort attribute list alphabetically, 
+     *                               may also be an assoc array containing 
+     *                               the keys 'sort', 'multiline', 'indent', 
+     *                               'linebreak' and 'entities'
+     * @param bool       $multiline  use linebreaks, if more than 
+     *                               one attribute is given
+     * @param string     $indent     string used for indentation of 
+     *                               multiline attributes
+     * @param string     $linebreak  string used for linebreaks of 
+     *                               multiline attributes
+     * @param int        $entities   setting for entities in attribute values 
+     *                               (one of XML_UTIL_ENTITIES_NONE, 
+     *                               XML_UTIL_ENTITIES_XML, 
+     *                               XML_UTIL_ENTITIES_XML_REQUIRED, 
+     *                               XML_UTIL_ENTITIES_HTML)
+     *
+     * @return string string representation of the attributes
+     * @access public
+     * @static
+     * @uses replaceEntities() to replace XML entities in attribute values
+     * @todo allow sort also to be an options array
+     */
+    function attributesToString($attributes, $sort = true, $multiline = false, 
+        $indent = '    ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
+    {
+        /*
+         * second parameter may be an array
+         */
+        if (is_array($sort)) {
+            if (isset($sort['multiline'])) {
+                $multiline = $sort['multiline'];
+            }
+            if (isset($sort['indent'])) {
+                $indent = $sort['indent'];
+            }
+            if (isset($sort['linebreak'])) {
+                $multiline = $sort['linebreak'];
+            }
+            if (isset($sort['entities'])) {
+                $entities = $sort['entities'];
+            }
+            if (isset($sort['sort'])) {
+                $sort = $sort['sort'];
+            } else {
+                $sort = true;
+            }
+        }
+        $string = '';
+        if (is_array($attributes) && !empty($attributes)) {
+            if ($sort) {
+                ksort($attributes);
+            }
+            if ( !$multiline || count($attributes) == 1) {
+                foreach ($attributes as $key => $value) {
+                    if ($entities != XML_UTIL_ENTITIES_NONE) {
+                        if ($entities === XML_UTIL_CDATA_SECTION) {
+                            $entities = XML_UTIL_ENTITIES_XML;
+                        }
+                        $value = XML_Util::replaceEntities($value, $entities);
+                    }
+                    $string .= ' ' . $key . '="' . $value . '"';
+                }
+            } else {
+                $first = true;
+                foreach ($attributes as $key => $value) {
+                    if ($entities != XML_UTIL_ENTITIES_NONE) {
+                        $value = XML_Util::replaceEntities($value, $entities);
+                    }
+                    if ($first) {
+                        $string .= ' ' . $key . '="' . $value . '"';
+                        $first   = false;
+                    } else {
+                        $string .= $linebreak . $indent . $key . '="' . $value . '"';
+                    }
+                }
+            }
+        }
+        return $string;
+    }
+
+    /**
+     * Collapses empty tags.
+     *
+     * @param string $xml  XML
+     * @param int    $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL)
+     *                      or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
+     *
+     * @return string XML
+     * @access public
+     * @static
+     * @todo PEAR CS - unable to avoid "space after open parens" error
+     *       in the IF branch
+     */
+    function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) 
+    {
+        if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) {
+            return preg_replace(
+                '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|'
+                . 'param)([^>]*)><\/\\1>/s',
+                '<\\1\\2 />',
+                $xml);
+        } else {
+            return preg_replace('/<(\w+)([^>]*)><\/\\1>/s', '<\\1\\2 />', $xml);
+        }
+    }
+
+    /**
+     * create a tag
+     *
+     * This method will call XML_Util::createTagFromArray(), which
+     * is more flexible.
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // create an XML tag:
+     * $tag = XML_Util::createTag('myNs:myTag', 
+     *     array('foo' => 'bar'), 
+     *     'This is inside the tag', 
+     *     'http://www.w3c.org/myNs#');
+     * </code>
+     *
+     * @param string $qname           qualified tagname (including namespace)
+     * @param array  $attributes      array containg attributes
+     * @param mixed  $content         the content
+     * @param string $namespaceUri    URI of the namespace
+     * @param int    $replaceEntities whether to replace XML special chars in 
+     *                                content, embedd it in a CData section 
+     *                                or none of both
+     * @param bool   $multiline       whether to create a multiline tag where 
+     *                                each attribute gets written to a single line
+     * @param string $indent          string used to indent attributes 
+     *                                (_auto indents attributes so they start 
+     *                                at the same column)
+     * @param string $linebreak       string used for linebreaks
+     * @param bool   $sortAttributes  Whether to sort the attributes or not
+     *
+     * @return string XML tag
+     * @access public
+     * @static
+     * @see createTagFromArray()
+     * @uses createTagFromArray() to create the tag
+     */
+    function createTag($qname, $attributes = array(), $content = null, 
+        $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, 
+        $multiline = false, $indent = '_auto', $linebreak = "\n", 
+        $sortAttributes = true)
+    {
+        $tag = array(
+            'qname'      => $qname,
+            'attributes' => $attributes
+        );
+
+        // add tag content
+        if ($content !== null) {
+            $tag['content'] = $content;
+        }
+
+        // add namespace Uri
+        if ($namespaceUri !== null) {
+            $tag['namespaceUri'] = $namespaceUri;
+        }
+
+        return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, 
+            $indent, $linebreak, $sortAttributes);
+    }
+
+    /**
+     * create a tag from an array
+     * this method awaits an array in the following format
+     * <pre>
+     * array(
+     *     // qualified name of the tag
+     *     'qname' => $qname        
+     *
+     *     // namespace prefix (optional, if qname is specified or no namespace)
+     *     'namespace' => $namespace    
+     *
+     *     // local part of the tagname (optional, if qname is specified)
+     *     'localpart' => $localpart,   
+     *
+     *     // array containing all attributes (optional)
+     *     'attributes' => array(),      
+     *
+     *     // tag content (optional)
+     *     'content' => $content,     
+     *
+     *     // namespaceUri for the given namespace (optional)
+     *     'namespaceUri' => $namespaceUri 
+     * )
+     * </pre>
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * $tag = array(
+     *     'qname'        => 'foo:bar',
+     *     'namespaceUri' => 'http://foo.com',
+     *     'attributes'   => array('key' => 'value', 'argh' => 'fruit&vegetable'),
+     *     'content'      => 'I\'m inside the tag',
+     * );
+     * // creating a tag with qualified name and namespaceUri
+     * $string = XML_Util::createTagFromArray($tag);
+     * </code>
+     *
+     * @param array  $tag             tag definition
+     * @param int    $replaceEntities whether to replace XML special chars in 
+     *                                content, embedd it in a CData section 
+     *                                or none of both
+     * @param bool   $multiline       whether to create a multiline tag where each 
+     *                                attribute gets written to a single line
+     * @param string $indent          string used to indent attributes 
+     *                                (_auto indents attributes so they start 
+     *                                at the same column)
+     * @param string $linebreak       string used for linebreaks
+     * @param bool   $sortAttributes  Whether to sort the attributes or not
+     *
+     * @return string XML tag
+     * @access public
+     * @static
+     * @see createTag()
+     * @uses attributesToString() to serialize the attributes of the tag
+     * @uses splitQualifiedName() to get local part and namespace of a qualified name
+     * @uses createCDataSection()
+     * @uses raiseError()
+     */
+    function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
+        $multiline = false, $indent = '_auto', $linebreak = "\n", 
+        $sortAttributes = true)
+    {
+        if (isset($tag['content']) && !is_scalar($tag['content'])) {
+            return XML_Util::raiseError('Supplied non-scalar value as tag content',
+            XML_UTIL_ERROR_NON_SCALAR_CONTENT);
+        }
+
+        if (!isset($tag['qname']) && !isset($tag['localPart'])) {
+            return XML_Util::raiseError('You must either supply a qualified name '
+                . '(qname) or local tag name (localPart).', 
+                XML_UTIL_ERROR_NO_TAG_NAME);
+        }
+
+        // if no attributes hav been set, use empty attributes
+        if (!isset($tag['attributes']) || !is_array($tag['attributes'])) {
+            $tag['attributes'] = array();
+        }
+
+        if (isset($tag['namespaces'])) {
+            foreach ($tag['namespaces'] as $ns => $uri) {
+                $tag['attributes']['xmlns:' . $ns] = $uri;
+            }
+        }
+
+        if (!isset($tag['qname'])) {
+            // qualified name is not given
+
+            // check for namespace
+            if (isset($tag['namespace']) && !empty($tag['namespace'])) {
+                $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart'];
+            } else {
+                $tag['qname'] = $tag['localPart'];
+            }
+        } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) {
+            // namespace URI is set, but no namespace
+
+            $parts = XML_Util::splitQualifiedName($tag['qname']);
+
+            $tag['localPart'] = $parts['localPart'];
+            if (isset($parts['namespace'])) {
+                $tag['namespace'] = $parts['namespace'];
+            }
+        }
+
+        if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) {
+            // is a namespace given
+            if (isset($tag['namespace']) && !empty($tag['namespace'])) {
+                $tag['attributes']['xmlns:' . $tag['namespace']] =
+                    $tag['namespaceUri'];
+            } else {
+                // define this Uri as the default namespace
+                $tag['attributes']['xmlns'] = $tag['namespaceUri'];
+            }
+        }
+
+        // check for multiline attributes
+        if ($multiline === true) {
+            if ($indent === '_auto') {
+                $indent = str_repeat(' ', (strlen($tag['qname'])+2));
+            }
+        }
+
+        // create attribute list
+        $attList = XML_Util::attributesToString($tag['attributes'], 
+            $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities);
+        if (!isset($tag['content']) || (string)$tag['content'] == '') {
+            $tag = sprintf('<%s%s />', $tag['qname'], $attList);
+        } else {
+            switch ($replaceEntities) {
+            case XML_UTIL_ENTITIES_NONE:
+                break;
+            case XML_UTIL_CDATA_SECTION:
+                $tag['content'] = XML_Util::createCDataSection($tag['content']);
+                break;
+            default:
+                $tag['content'] = XML_Util::replaceEntities($tag['content'], 
+                    $replaceEntities);
+                break;
+            }
+            $tag = sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'],
+                $tag['qname']);
+        }
+        return $tag;
+    }
+
+    /**
+     * create a start element
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // create an XML start element:
+     * $tag = XML_Util::createStartElement('myNs:myTag', 
+     *     array('foo' => 'bar') ,'http://www.w3c.org/myNs#');
+     * </code>
+     *
+     * @param string $qname          qualified tagname (including namespace)
+     * @param array  $attributes     array containg attributes
+     * @param string $namespaceUri   URI of the namespace
+     * @param bool   $multiline      whether to create a multiline tag where each 
+     *                               attribute gets written to a single line
+     * @param string $indent         string used to indent attributes (_auto indents
+     *                               attributes so they start at the same column)
+     * @param string $linebreak      string used for linebreaks
+     * @param bool   $sortAttributes Whether to sort the attributes or not
+     *
+     * @return string XML start element
+     * @access public
+     * @static
+     * @see createEndElement(), createTag()
+     */
+    function createStartElement($qname, $attributes = array(), $namespaceUri = null,
+        $multiline = false, $indent = '_auto', $linebreak = "\n", 
+        $sortAttributes = true)
+    {
+        // if no attributes hav been set, use empty attributes
+        if (!isset($attributes) || !is_array($attributes)) {
+            $attributes = array();
+        }
+
+        if ($namespaceUri != null) {
+            $parts = XML_Util::splitQualifiedName($qname);
+        }
+
+        // check for multiline attributes
+        if ($multiline === true) {
+            if ($indent === '_auto') {
+                $indent = str_repeat(' ', (strlen($qname)+2));
+            }
+        }
+
+        if ($namespaceUri != null) {
+            // is a namespace given
+            if (isset($parts['namespace']) && !empty($parts['namespace'])) {
+                $attributes['xmlns:' . $parts['namespace']] = $namespaceUri;
+            } else {
+                // define this Uri as the default namespace
+                $attributes['xmlns'] = $namespaceUri;
+            }
+        }
+
+        // create attribute list
+        $attList = XML_Util::attributesToString($attributes, $sortAttributes, 
+            $multiline, $indent, $linebreak);
+        $element = sprintf('<%s%s>', $qname, $attList);
+        return  $element;
+    }
+
+    /**
+     * create an end element
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // create an XML start element:
+     * $tag = XML_Util::createEndElement('myNs:myTag');
+     * </code>
+     *
+     * @param string $qname qualified tagname (including namespace)
+     *
+     * @return string XML end element
+     * @access public
+     * @static
+     * @see createStartElement(), createTag()
+     */
+    function createEndElement($qname)
+    {
+        $element = sprintf('</%s>', $qname);
+        return $element;
+    }
+
+    /**
+     * create an XML comment
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // create an XML start element:
+     * $tag = XML_Util::createComment('I am a comment');
+     * </code>
+     *
+     * @param string $content content of the comment
+     *
+     * @return string XML comment
+     * @access public
+     * @static
+     */
+    function createComment($content)
+    {
+        $comment = sprintf('<!-- %s -->', $content);
+        return $comment;
+    }
+
+    /**
+     * create a CData section
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // create a CData section
+     * $tag = XML_Util::createCDataSection('I am content.');
+     * </code>
+     *
+     * @param string $data data of the CData section
+     *
+     * @return string CData section with content
+     * @access public
+     * @static
+     */
+    function createCDataSection($data)
+    {
+        return sprintf('<![CDATA[%s]]>', 
+            preg_replace('/\]\]>/', ']]]]><![CDATA[>', strval($data)));
+
+    }
+
+    /**
+     * split qualified name and return namespace and local part
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // split qualified tag
+     * $parts = XML_Util::splitQualifiedName('xslt:stylesheet');
+     * </code>
+     * the returned array will contain two elements:
+     * <pre>
+     * array(
+     *     'namespace' => 'xslt',
+     *     'localPart' => 'stylesheet'
+     * );
+     * </pre>
+     *
+     * @param string $qname     qualified tag name
+     * @param string $defaultNs default namespace (optional)
+     *
+     * @return array array containing namespace and local part
+     * @access public
+     * @static
+     */
+    function splitQualifiedName($qname, $defaultNs = null)
+    {
+        if (strstr($qname, ':')) {
+            $tmp = explode(':', $qname);
+            return array(
+                'namespace' => $tmp[0],
+                'localPart' => $tmp[1]
+            );
+        }
+        return array(
+            'namespace' => $defaultNs,
+            'localPart' => $qname
+        );
+    }
+
+    /**
+     * check, whether string is valid XML name
+     *
+     * <p>XML names are used for tagname, attribute names and various
+     * other, lesser known entities.</p>
+     * <p>An XML name may only consist of alphanumeric characters,
+     * dashes, undescores and periods, and has to start with a letter
+     * or an underscore.</p>
+     *
+     * <code>
+     * require_once 'XML/Util.php';
+     *
+     * // verify tag name
+     * $result = XML_Util::isValidName('invalidTag?');
+     * if (is_a($result, 'PEAR_Error')) {
+     *    print 'Invalid XML name: ' . $result->getMessage();
+     * }
+     * </code>
+     *
+     * @param string $string string that should be checked
+     *
+     * @return mixed true, if string is a valid XML name, PEAR error otherwise
+     * @access public
+     * @static
+     * @todo support for other charsets
+     * @todo PEAR CS - unable to avoid 85-char limit on second preg_match
+     */
+    function isValidName($string)
+    {
+        // check for invalid chars
+        if (!preg_match('/^[[:alpha:]_]$/', $string{0})) {
+            return XML_Util::raiseError('XML names may only start with letter '
+                . 'or underscore', XML_UTIL_ERROR_INVALID_START);
+        }
+
+        // check for invalid chars
+        if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/',
+            $string)
+        ) {
+            return XML_Util::raiseError('XML names may only contain alphanumeric '
+                . 'chars, period, hyphen, colon and underscores', 
+                XML_UTIL_ERROR_INVALID_CHARS);
+        }
+        // XML name is valid
+        return true;
+    }
+
+    /**
+     * replacement for XML_Util::raiseError
+     *
+     * Avoids the necessity to always require
+     * PEAR.php
+     *
+     * @param string $msg  error message
+     * @param int    $code error code
+     *
+     * @return PEAR_Error
+     * @access public
+     * @static
+     * @todo PEAR CS - should this use include_once instead?
+     */
+    function raiseError($msg, $code)
+    {
+        require_once 'PEAR.php';
+        return PEAR::raiseError($msg, $code);
+    }
+}
+?>
