便利そうな関数がいっぱいあったので、その中から cbxmlbreak & cbxmlattrs を使った単機能エクステンションの習作を。
XML (ていうか SGML) のテキストデータを配列に分割する関数です。DOM や正規表現でゴリゴリするよりシンプルな処理に。
普段は CodeGen_PECL は雛形生成だけで、コードは C のソースファイルを直接編集していますが、今回は spec ファイルに全部書いてみました。
まじめに作り込むときは CodeGen_PECL の吐くコードはちょっと不満があるけど、こういったものをサクッと作るには良いですね。
<?xml version="1.0" ?> <extension name="splitxml" version="0.0.1"> <summary>splitxml</summary> <license>LGPL</license> <release> <version>0.0.1</version> <date>2007-07-11</date> <state>devel</state> <notes>TEST</notes> </release> <deps language="c" platform="all"> <with name="qdbm" mode="pkg-config"> <header name="cabin.h"/> <lib name="qdbm"/> </with> </deps> <function role="public" name="splitxml"> <proto>array splitxml(string xml[, bool remove_comments])</proto> <code><![CDATA[ CBLIST *nlist = cbxmlbreak(xml, remove_comments); int index = 0; int len = 0; const char *node; if (!nlist) { php_error(E_WARNING, "cbxmlbreak() failed."); zval_dtor(return_value); RETURN_FALSE; } while (NULL != (node = cblistval(nlist, index, &len))) { if (len > 1 && node[0] == '<' && node[1] != '/' && node[1] != '!') { CBMAP *amap = cbxmlattrs(node); const char *key; zval *tmp; if (!amap) { php_error(E_WARNING, "cbxmlattr() failed."); cblistclose(nlist); zval_dtor(return_value); RETURN_FALSE; } MAKE_STD_ZVAL(tmp); array_init(tmp); cbmapiterinit(amap); while (NULL != (key = cbmapiternext(amap, &len))) { if (len == 0) { char *tag = cbsprintf("<%s>", cbmapiterval(key, NULL)); (void)add_next_index_string(tmp, tag, 1); free(tag); } else { (void)add_assoc_string(tmp, (char *)key, (char *)cbmapiterval(key, NULL), 1); } } cbmapclose(amap); (void)add_next_index_zval(return_value, tmp); } else { (void)add_next_index_string(return_value, (char *)node, 1); } index++; } cblistclose(nlist); ]]></code> </function> </extension>
他にも MIME および CSV 系の関数は PHP にありそうでなかったり、あっても実装が微妙だったりするのでラップする価値ありです。