myxml.c

最終更新:2009/11/30

myxml.c

001: /* myxml.c
002:  * APR-UTIL の XML API を使うサンプル
003:  * ・getElementsByTagName と getElementById 
004:  */
005: 
006: #include "myxml.h"
007: 
008: /*
009:  * apr_xml_elem* の配列のイテレーション
010:  * func は配列内の apr_xml_elem* を処理するコールバック関数
011:  * void func (void *func_ctx, apr_xml_elem * elem);
012:  */
013: 
014: void my_apr_xml_elem_array_do(
015:   apr_array_header_t *arr
016:   , void *func
017:   , void *func_ctx
018: ) {
019:   int i=0;
020:   void (*f)(void *,apr_xml_elem*) = func;
021:   if (!arr || !f) {
022:     return;
023:   }
024:   
025:   for (i=0; i<arr->nelts; i++) {
026:     apr_xml_elem *elem = ((apr_xml_elem **)arr->elts)[i];
027:     f(func_ctx, elem);
028:   }
029: }
030: 
031: /*
032:  * エレメントのCDATAを返す関数
033:  * 返り値:
034:  *   エレメントのCDATAの文字列
035:  * メモ:
036:  * n->first_cdata.first から next メンバ変数をたどって text メンバ変数の
037:  * 文字列をコンカテネートする。
038:  */
039: 
040: char * concat_cdata(
041:   apr_xml_elem *n    /* IN: 対象エレメント */
042:   , apr_pool_t *pool /* IN: メモリプール */
043: ) {
044:   char *buf = NULL;
045:   apr_text *x = n->first_cdata.first;
046:   for (; x; x=x->next) {
047:     if (x->text) {
048:       if (!buf) {
049:         buf = apr_pstrdup(pool, x->text);
050:       } else {
051:         buf = apr_pstrcat(pool, buf, x->text, NULL);
052:       }
053:     }
054:   }
055:   return buf;
056: }
057: 
058: /*
059:  * エレメントから、指定した名前のアトリビュートの値を検索する関数
060:  */
061: 
062: char const * getAttribute(
063:   apr_xml_elem *n /* IN: 対象エレメント */
064:   , char *aname   /* IN: 検索アトリビュート名 */
065: ) {
066:   apr_xml_attr *attr = NULL;
067:   if (NULL == n) {
068:     return NULL;
069:   }
070:   
071:   for (attr=n->attr; attr; attr=attr->next) {
072:     if (!strcmp(attr->name, aname))
073:       return attr->value;
074:   }
075: 
076:   return NULL;
077: }
078: 
079: /* getElementsByTagName の補助関数
080:  * 戻り値:
081:  *   検索タグ名にマッチしたエレメントを保持する配列
082:  */
083:  
084: static apr_array_header_t *_getElementsByTagName(
085:   apr_array_header_t *arr /* IN/OUT: マッチしたエレメントを保持する配列 */
086:   , apr_xml_elem *n       /* IN: 対象エレメント */
087:   , char *tagname         /* IN: 検索タグ名 */
088: ) {
089: 
090:   if (!strcmp(n->name, tagname)) {
091:     *(const apr_xml_elem **)apr_array_push(arr) = n;
092:   }
093:   if (n->first_child) {
094:     _getElementsByTagName(arr, n->first_child, tagname);
095:   }
096:   if (n->next) {
097:     _getElementsByTagName(arr, n->next, tagname);
098:   }
099:   return arr;
100: }
101: 
102: /* 指定エレメント配下の、検索タグ名にマッチするエレメント群を検索する関数
103:  * 戻り値:
104:  *   検索タグ名にマッチしたエレメントを保持する配列
105:  *   子エレメントが存在しない場合はヌル。
106:  */
107: 
108: apr_array_header_t *getElementsByTagNameFromElement(
109:   apr_pool_t *pool   /* IN: メモリプール */
110:   , apr_xml_elem *n  /* IN: 対象エレメント */
111:   , char *tagname    /* IN: 検索タグ名 */
112: ) {
113:   apr_array_header_t *arr=NULL;
114:   
115:   if (NULL == tagname || NULL == n || NULL == n->first_child) {
116:     return NULL;
117:   }
118:   
119:   arr = apr_array_make(pool, 1, sizeof(apr_xml_elem *));
120:   return _getElementsByTagName(arr, n->first_child, tagname);
121: }
122: 
123: /* XMLドキュメント内の検索タグ名にマッチしたエレメント群を検索する関数
124:  * 戻り値:
125:  * 検索タグ名にマッチしたエレメントを保持する配列
126:  */
127: 
128: apr_array_header_t *getElementsByTagName(
129:   apr_pool_t *pool   /* IN: メモリプール */
130:   , apr_xml_doc *doc /* IN: 対象XMLドキュメント */
131:   , char *tagname    /* IN: 検索タグ名 */
132: ) {
133:   apr_array_header_t *arr=NULL;
134:   
135:   if (NULL == doc || NULL == tagname || NULL == doc->root) {
136:     return NULL;
137:   }
138:   
139:   arr = apr_array_make(pool, 1, sizeof(apr_xml_elem *));
140:   return _getElementsByTagName(arr, doc->root, tagname);
141: }
142: 
143: /* getElementById の補助関数
144:  * 戻り値:
145:  * 検索タグ名にマッチしたエレメント
146:  */
147: 
148: apr_xml_elem * _getElementById (
149:   apr_xml_elem *n /* IN: 対象エレメント */
150:   , char *id      /* IN: 検索ID */
151: ) {
152:   apr_xml_elem *r=NULL;
153:   apr_xml_attr *a = n->attr;
154:   for (; a; a = a->next) {
155:     if (!strcmp(a->value, id)) {
156:       return n;
157:     }
158:   }
159:   if (n->first_child && (r = _getElementById(n->first_child, id))) {
160:     return r;
161:   }
162:   if (n->next) {
163:     return _getElementById(n->next, id);
164:   }
165:   
166:   return NULL;
167: }
168: 
169: /* XMLドキュメント内の検索IDにマッチしたエレメントを検索する関数
170:  * 戻り値:
171:  *   検索IDにマッチしたエレメント
172:  */
173: 
174: apr_xml_elem * getElementById (
175:   apr_xml_doc *doc  /* IN: 対象XMLドキュメント */
176:   , char *id        /* IN: 検索ID */
177: ) {
178:   if (NULL == doc || NULL == id || NULL == doc->root) {
179:     return NULL;
180:   }
181:   
182:   return _getElementById (doc->root, id);
183: }
184: 
185: /* printElement[Rec] の補助関数。アトリビュートの表示
186:  * 戻り値:
187:  *   なし
188:  */
189: static void _printAttr (
190:   apr_file_t *out      /* IN: 出力先ファイルポインタ */
191:   , apr_xml_attr *attr /* IN: 表示対象アトリビュート */
192: ) {
193:   for (; attr; attr=attr->next) {
194:     apr_file_printf(out, "[%s]=[%s]", attr->name, attr->value);
195:   }
196: }
197: 
198: /*
199:  * 空白文字の検査
200:  */
201: 
202: static int _is_spaces(const char *s) {
203:   char *x=(char *)s;
204:   if (NULL) {
205:     return 1;
206:   }
207:   for(;*x;x++) {
208:     if (*x!='\t' && *x!='\r' && *x!='\n' && *x!=' ') {
209:       return 0;
210:     }
211:   }
212:   return 1;
213: }
214: 
215: /* printElement[Rec] の補助関数。CDATAの表示
216:  * 戻り値:
217:  *   なし
218:  */
219: 
220: static void _printCDATA(
221:   apr_file_t *out   /* IN: 出力先ファイルポインタ */
222:   , apr_text *cdata /* IN: 表示対象CDATA */
223: ) {
224:   for (; cdata; cdata=cdata->next) {
225:     if (! _is_spaces(cdata->text))
226:       apr_file_printf(out, "%s", cdata->text);
227:   }
228: }
229: 
230: /* エレメントの表示。指定されたエレメントのタグ名、アトリビュート、
231:  * 直下のCDATAの表示のみ。NS 非対応。
232:  * 戻り値:
233:  *   なし
234:  * メモ:
235:  *   apr_xml_to_text 関数が既に用意されている。どちらかというと、apr_xml_elem
236:  *   の構造の勉強用。
237:  */
238: 
239: void printElement (
240:   apr_file_t *out      /* IN: 出力先ファイルポインタ */
241:   , apr_xml_elem *elem /* IN: 表示対象エレメント */
242: ) {
243:   if (NULL == elem || NULL == out) {
244:     return;
245:   }
246:   apr_file_printf(out, "<%s", elem->name);
247:   if (elem->attr) {
248:     _printAttr(out, elem->attr);
249:   }
250:   if (elem->first_cdata.first) {
251:     apr_file_printf(out, ">");
252:     _printCDATA(out, elem->first_cdata.first);
253:     apr_file_printf(out, "</%s>", elem->name);
254:   } else {
255:     apr_file_printf(out, "/>");
256:   }
257: }
258: 
259: /* エレメントの表示。指定されたエレメントのタグ名、アトリビュート、
260:  * 直下のCDATAの表示に加え、子エレメント(child)と続くエレメントも再帰的に表示。
261:  * 戻り値:
262:  *   なし
263:  * メモ:
264:  *   apr_xml_to_text 関数が既に用意されている。どちらかというと、apr_xml_elem
265:  *   の構造の勉強用。
266:  */
267: void printElementRec (
268:   apr_file_t *out      /* IN: 出力先ファイルポインタ */
269:   , apr_xml_elem *elem /* IN: 表示対象エレメント */
270: ) {
271:   if (NULL == elem || NULL == out) {
272:     return;
273:   }
274:   apr_file_printf(out, "<%s", elem->name);
275: 
276:   if (elem->attr) {
277:     _printAttr(out, elem->attr);
278:   }
279:   if (APR_XML_ELEM_IS_EMPTY(elem)) {
280:     apr_file_printf(out, "/>");
281:   } else {
282:     apr_file_printf(out, ">");
283:     if (elem->first_cdata.first) {
284:       _printCDATA(out, elem->first_cdata.first);
285:     }
286:     if (elem->first_child) {
287:       printElementRec(out, elem->first_child);
288:     }
289:     apr_file_printf(out, "</%s>", elem->name);
290:   }
291:   if (elem->following_cdata.first) {
292:     _printCDATA(out, elem->following_cdata.first);
293:   }
294:   if (elem->next) {
295:     printElementRec(out, elem->next);
296:   }
297: }
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)