#include "txml.h"
/**
Tiny XML txml.c v1.0 '09 2/10
サブセット版 整形式XML 簡易パーサ
全てのパターンのパース可能性を保障するものではありません
複雑な XMLはパースできません.
以外の ..... ?> と は処理しない(読み込みは行う)
エンティティは処理しない.
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
/**
tXML* xml_parse(char* pp)
機能:XMLデータを解釈して,tXMLのツリー構造に格納する.
引数:pp -- XMLデータへのポインタ.
戻り値: return -- XMLデータを格納した tXMLのアンカーへのポインタ
エラーを起こした場合 ->state に XML_PARSED 以外の値(0以下)が入る.
エラーの場合は,->next 以下にはエラーを起こす直前までの内容が保存される
*/
tXML* xml_parse(char* pp)
{
tXML* xml;
tXML* tag;
xml = new_tTree_node(); // アンカー
xml->ldat.id = XML_ANCHOR_TAG;
// パース
tag = xml_partial_parse(xml, pp, TRUE);
if (tag->state<0) return xml;
// 元に戻ったか?
if (xml==tag) {
xml->state = XML_PARSED;
}
else {
xml->state = XML_PARSE_ERROR;
return xml;
}
// XML rootの数
if (xml->next!=NULL) {
int n = 0;
tag = xml->next;
while(tag!=NULL) {
if (tag->ldat.id==XML_TAG_NAME) n++;
tag = tag->ysis;
}
if (n!=1) xml->state = XML_MULTI_ROOT;
}
else xml->state = XML_DEFAULT_STATE;
return xml;
}
/**
tXML* xml_parse_seq(tXML* xml, char* pp)
機能:部分的な XMLデータを解釈して,tXMLのツリー構造に格納する.
完全な XMLデータでなくても解釈できるところまでは解釈する.
xmlが NULLの場合は自動的にツリーを作る.
断片的に XMLデータを入力する場合に使用する.
引数: pp -- XMLデータへのポインタ.
xml -- XMLデータを格納するツリー構造体の先頭へのポインタ.ツリーの途中のタグでも可
戻り値: return -- XMLツリーデータのアンカーへのポインタ
->altp に最後に処理したタグへのポインタが格納される.
解釈が不完全の場合は ->state に状態の値が入る.
*/
tXML* xml_parse_seq(tXML* xml, char* pp)
{
int skip = FALSE;
tXML* tag;
if (xml==NULL) {
xml = new_tTree_node();
xml->ldat.id = XML_ANCHOR_TAG;
skip = TRUE;
}
else {
tXML* top = find_xml_top(xml);
if (top==xml) top->state = XML_DEFAULT_STATE;
}
tag = xml_partial_parse(xml, pp, skip);
xml = find_xml_top(xml);
xml->altp = tag;
if (xml!=tag) return xml;
if (tag->state==0) xml->state = XML_PARSED;
else xml->state = tag->state;
if (xml->next!=NULL) {
int n = 0;
tag = xml->next;
while(tag!=NULL) {
if (tag->ldat.id==XML_TAG_NAME) n++;
tag = tag->ysis;
}
if (n!=1) xml->state = XML_MULTI_ROOT;
}
else xml->state = XML_DEFAULT_STATE;
return xml;
}
/**
tXML* xml_parse_file(char* fn)
機能:ファイルから読み込んでパースする.
引数:fn -- 読み込むファイル名
戻り値: return -- XMLデータを格納した tXMLのアンカーへのポインタ
*/
tXML* xml_parse_file(char* fn)
{
tXML* xml = NULL;
Buffer buf;
buf = read_Buffer_file(fn);
if (buf.buf!=NULL) {
xml = xml_parse((char*)(buf.buf));
free_Buffer(&buf);
}
return xml;
}
/**
tXML* xml_partial_parse(tXML* xml, char* pp, int skip)
機能:部分的な XMLデータを解釈して,tXMLのツリー構造に格納する.
完全な XMLデータでなくても解釈できるところまでは解釈する.
パーサのメイン関数.ただし,ユーザが直接この関数を使用することは多分無い.
引数: pp -- XMLデータへのポインタ.
xml -- XMLデータを格納するツリー構造体の先頭へのポインタ.
skip - 最初のデータ(タイトルなど)をスキップするか? TRUE or FLASE
戻り値: return -- 最後に処理したタグノードへのポインタ.
エラーの場合は ->state に 0未満の値が入る.
ppが NULLの場合は xml, xmlが NULLの場合は NULLが返る.
*/
tXML* xml_partial_parse(tXML* xml, char* pp, int skip)
{
int n, tag_end;
char* tag_name = NULL;
char* tag_attr = NULL;
char* value = NULL;
if (pp ==NULL) return xml;
if (xml==NULL) return NULL;
if (skip) while (*pp!='\0' && *pp!='<') pp++;
while (*pp!='\0') {
n = 1;
if (*pp=='<') {
// End TAG >
if (*(pp+1)=='/') {
if (xml->state==XML_TAG_STARTED) {
n = xml_parse_end_tag(pp, &tag_name);
if (n>0) {
if (tag_name!=NULL && xml->ldat.key.buf!=NULL) {
if (!strcmp((const char*)tag_name, (const char*)(xml->ldat.key.buf))) {
xml->state = XML_TAG_ENDED;
if (xml->prev!=NULL) xml = xml->prev;
else n = xml->state = XML_SEQUENCE_ERROR;
}
else n = xml->state = XML_PARSE_ERROR;
}
else n = xml->state = XML_PARSE_ERROR;
}
else xml->state = n; // エラー
}
else n = xml->state = XML_PARSE_ERROR;
}
// Comment TAG
else if (!strncmp(pp+1, "!--", 3)) {
n = xml_parse_comment_tag(pp, &value);
if (n>0) {
xml = add_tTree_node_bystr(xml, XML_COMMENT_TAG, 0, XML_COMMENT_TAG_KEY, value, NULL, 0);
xml->state = XML_TAG_EMPTY;
if (xml->prev!=NULL) xml = xml->prev;
else n = xml->state = XML_SEQUENCE_ERROR;
}
}
// Data TAG
else if (*(pp+1)=='!') {
n = xml_parse_data_tag(pp, &value);
if (n>0) {
xml = add_tTree_node_bystr(xml, XML_DATA_TAG, 0, XML_DATA_TAG_KEY, value, NULL, 0);
xml->state = XML_TAG_EMPTY;
if (xml->prev!=NULL) xml = xml->prev;
else n = xml->state = XML_SEQUENCE_ERROR;
}
}
// Processing TAG ?>
else if (*(pp+1)=='?') {
n = xml_parse_processing_tag(pp, &tag_name, &tag_attr);
if (n>0) {
if (!strncasecmp("xml", tag_name, 3)) {
tList* lp = xml_parse_attr(tag_attr);
xml = add_tTree_node_bystr(xml, XML_DOC_TAG, 0, tag_name, NULL, NULL, 0);
xml->ldat.lst = lp;
}
else {
xml = add_tTree_node_bystr(xml, XML_PROCESS_TAG, 0, tag_name, tag_attr, NULL, 0);
}
xml->state = XML_TAG_EMPTY;
if (xml->prev!=NULL) xml = xml->prev;
else n = xml->state = XML_SEQUENCE_ERROR;
}
}
// Start TAG < >
else {
n = xml_parse_start_tag(pp, &tag_name, &tag_attr, &tag_end);
if (n>0) {
tList* lp = xml_parse_attr(tag_attr);
xml = add_tTree_node_bystr(xml, XML_TAG_NAME, 0, tag_name, NULL, NULL, 0);
xml->ldat.lst = lp;
if (tag_end) {
xml->state = XML_TAG_EMPTY;
if (xml->prev!=NULL) xml = xml->prev;
else n = xml->state = XML_SEQUENCE_ERROR;
}
else {
int m;
xml->state = XML_TAG_STARTED;
// タグ値
m = xml_parse_content(pp+n, &value); // 0 が返る可能性がある
if (m>=0) {
n += m;
if (value!=NULL) {
xml = add_tTree_node_bystr(xml, XML_TAG_CONTENT, 0, value, NULL, NULL, 0);
xml->state = XML_TAG_ENDED;
if (xml->prev!=NULL) {
xml = xml->prev;
xml->ldat.lv++;
}
else n = xml->state = XML_SEQUENCE_ERROR;
}
}
else n = xml->state = m; // エラー
}
}
}
freeNull(tag_name);
freeNull(tag_attr);
freeNull(value);
}
// Content (断片的に入力したXMLが content の途中で終わっている場合など)
else {
if (xml->state==XML_TAG_STARTED) {
n = xml_parse_content(pp, &value);
if (n>0) {
if (value!=NULL) {
xml = add_tTree_node_bystr(xml, XML_TAG_CONTENT, 0, value, NULL, NULL, 0);
xml->state = XML_TAG_ENDED;
if (xml->prev!=NULL) {
xml = xml->prev;
xml->ldat.lv++;
}
else n = xml->state = XML_SEQUENCE_ERROR;
}
}
else n = xml->state = XML_PARSE_ERROR;
freeNull(value);
}
else n = xml->state = XML_PARSE_ERROR;
}
// エラー
if (n<=0) return xml;
pp += n;
while (*pp==' ' || *pp==TAB || *pp==LF || *pp==CR) pp++;
}
return xml;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Paese of TAG
//
/**
int xml_parse_start_tag(char* pp, char** tag_name, char** tag_attr, int* tag_end)
機能:XMLの開始タグを処理する.処理できるタグの型は
注)この関数では,属性部分(*tag_attr)の解釈は行われないので,それは xml_parse_attr()
で行う必要がある.
引数:pp -- タグへのポインタ.'<' を指すポインタ.
*tag_name -- タグの名前を格納するポインタ.
*tag_attr -- タグの属性部分を格納するポインタ.
*tag_end -- タグが単独で閉じているかどうかを格納する変数.
戻り値:
return -- 1>=: タグ全体の長さ.0 が返ることは無い.
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*tag_name -- タグの名前が格納される.要free
*tag_attr -- タグの属性部分が格納される.処理(解釈)は行われない.要free
*tag_end -- タグが単独で閉じている場合(Empty Tag)は TRUE, そうでない場合は FALSE.要free
*/
int xml_parse_start_tag(char* pp, char** tag_name, char** tag_attr, int* tag_end)
{
int nn, mm;
char* pt;
*tag_end = FALSE;
*tag_name = NULL;
*tag_attr = NULL;
if (*pp!='<') return XML_PARSE_ERROR;
pt = pp = pp + 1;
pt = skip_char(pt, " />");
if (pt==NULL) return XML_PARSE_ERROR;
nn = mm = (int)(pt - pp);
if (mm==0) return XML_PARSE_ERROR;
nn = nn + 1;
*tag_name = (char*)malloc((size_t)(mm + 1));
if (*tag_name==NULL) return XML_MEMORY_ERROR;
memcpy(*tag_name, pp, mm);
(*tag_name)[mm] = '\0';
//print_message("START --> %s %d\n", *tag_name, (int)strlen(*tag_name));
if (isnot_xml_name((unsigned char*)(*tag_name))) return XML_PARSE_ERROR;
// Empty TAG
if (*pt=='/') {
if (*(pt+1)!='>') {
freeNull(*tag_name);
return XML_PARSE_ERROR;
}
nn += 1;
*tag_end = TRUE;
//print_message("END --> %s %d\n", *tag_name, (int)strlen(*tag_name));
}
// Attribute
else if (*pt==' ') {
pp = pt = pt + 1;
while (*pt==' ' || *pt==TAB || *pt==LF || *pt==CR) pt++;
nn += (int)(pt - pp) + 1;
pp = pt;
pt = skip_char(pt, "/>");
if (pt==NULL) {
freeNull(*tag_name);
return XML_PARSE_ERROR;
}
mm = (int)(pt - pp);
if (mm>0) {
*tag_attr = (char*)malloc((size_t)(mm + 1));
if (*tag_attr==NULL) {
freeNull(*tag_name);
return XML_MEMORY_ERROR;
}
memcpy(*tag_attr, pp, mm);
(*tag_attr)[mm] = '\0';
nn += mm;
//print_message("ATTR --> %s %d\n", *tag_attr, (int)strlen(*tag_attr));
}
if (*pt=='/') {
if (*(pt+1)!='>') {
freeNull(*tag_name);
freeNull(*tag_attr);
return XML_PARSE_ERROR;
}
nn += 1;
*tag_end = TRUE;
//print_message("END --> %s %d\n", *tag_name, (int)strlen(*tag_name));
}
}
//else {} *pt=='>'
return nn + 1;
}
/**
int xml_parse_end_tag(char* pp, char** tag_name)
機能:XMLの終了タグを処理する.処理できるタグの型は
引数:pp -- タグへのポインタ.'<' を指すポインタ.
*tag_name -- タグの名前を格納するポインタ.
戻り値:
return -- 0>: タグ全体の長さ.0 が返ることは無い.
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*tag_name -- タグの名前が格納される.要free
*/
int xml_parse_end_tag(char* pp, char** tag_name)
{
int nn, mm;
char* pt;
char* work;
if (pp==NULL) return XML_PARSE_ERROR;
*tag_name = NULL;
if (strncmp(pp ,"", 2)) return XML_PARSE_ERROR;
pt = pp = pp + 2;
pt = skip_char(pt, ">");
if (pt==NULL) return XML_PARSE_ERROR;
nn = mm = (int)(pt - pp);
if (mm==0) return XML_PARSE_ERROR;
nn += 2;
work = (char*)malloc((size_t)(mm+1));
if (work==NULL) return XML_MEMORY_ERROR;
memcpy(work, pp, mm);
work[mm] = '\0';
*tag_name = pack_head_tail_char(work, ' ');
free(work);
//print_message("END --> %s %d\n", *tag_name, (int)strlen(*tag_name));
return nn + 1;
}
/**
int xml_parse_content(char* pp, char** content)
機能:XMLのコンテントを処理する. content
値の前後の空白,TAB, LF, CRは削除される.
引数:pp -- コンテントの先頭へのポインタ.Start Tagの '>' の次を指すポインタ.
*content -- コンテントを格納するポインタ.コンテントがない場合は NULLでも可.
戻り値:
return -- 0>=: タグ値部の全体の長さ.0 が返る可能性もある(の場合)
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*content -- コンテントが格納される.前後の 空白, TAB, LF, CRは削除されている.要free
*/
int xml_parse_content(char* pp, char** content)
{
int nn=0, mm;
char* pt;
char* work;
if (pp==NULL || content==NULL) return XML_PARSE_ERROR;
*content = NULL;
while (*pp==' ' || *pp==TAB || *pp==LF || *pp==CR) {
pp++;
nn++;
}
if (*pp=='<') return nn; // <
pt = pp;
while (*pt!='<' && *pt!='\0') pt++;
mm = (int)(pt - pp);
if (mm==0) return nn;
nn += mm;
work = (char*)malloc((size_t)(mm+1));
if (work==NULL) return XML_MEMORY_ERROR;
memcpy(work, pp, mm);
work[mm] = '\0';
*content = pack_head_tail_char(work, ' ');
free(work);
//print_message("VALUE --> %s %d\n", *content, (int)strlen(*content));
return nn;
}
/**
tList* xml_parse_attr(char* pp)
機能:XMLのタグ属性を解釈して,リスト(tList)にする. 解釈する形式は AAA="GGG" xxxx="1234"
引数:テキストで保存されている属性へのポインタ.
戻り値:生成したリストの先頭へのポインタ.
パースエラーの場合は state に XML_PARSE_ERROR が設定される.正常に終了した場合
は XML_TAG_ENDED が設定される.
*/
tList* xml_parse_attr(char* pp)
{
int sz;
char* nm;
char* vl;
char* pt;
char qt;
tList* lp = NULL;
tList* lt = NULL;
// 作業メモリの確保
if (pp==NULL) return NULL;
sz = (int)strlen((const char*)pp) + 1;
nm = (char*)malloc(sz);
if (nm==NULL) return NULL;
vl = (char*)malloc(sz);
if (vl==NULL) {
free(nm);
return NULL;
}
// Parse for AAA="BBB" CCC="DDDD"
while (*pp==' ' && *pp!='\0') pp++;
while (*pp!='\0') {
pt = pp;
while (*pt!='=' && *pt!='\0') pt++;
if (*pt=='\0') {
if (lt!=NULL) lt->state = XML_PARSE_ERROR;
break;
}
sz = (int)(pt - pp);
memcpy(nm, pp, (size_t)sz);
nm[sz] = '\0';
pt++;
if (*pt!='"' && *pt!='\'') {
if (lt!=NULL) lt->state = XML_PARSE_ERROR;
break;
}
else qt = *pt;
pt++;
pp = pt;
while(*pt!=qt && *pt!='\0') pt++;
if (*pt=='\0') {
if (lt!=NULL) lt->state = XML_PARSE_ERROR;
break;
}
sz = (int)(pt - pp);
memcpy(vl+1, pp, (size_t)sz);
vl[0] = qt;
vl[sz+1] = qt;
vl[sz+2] = '\0';
lp = add_tList_node_str(lp, nm, vl);
if (lt==NULL) lt = lp;
pp = pt + 1;
if (*pp!=' ' && *pp!='\0') {
lt->state = XML_PARSE_ERROR;
break;
}
while (*pp==' ' && *pp!='\0') pp++;
}
//
free(nm);
free(vl);
if (lt!=NULL) {
if (lt->state!=XML_PARSE_ERROR) lt->state = XML_TAG_ENDED;
}
return lt;
}
/**
int xml_parse_processing_tag(char* pp, char** tag_name, char** tag_attr)
機能:XMLのプロセッシングタグを処理する.処理できるタグの型は
プロセッシング部分は解釈せずに,そのまま tag_name, tag_attrに格納される.
引数:pp -- タグへのポインタ.'<' を指すポインタ.
*tag_name -- プロセッシングの名前部分を格納するポインタ.
*tag_attr -- プロセッシングの属性部分を格納するポインタ.
戻り値:
return -- 0>: タグ全体の長さ.0 が返ることは無い.
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*tag_name -- プロセッシングの名前部分が格納される.要free
*tag_attr -- プロセッシングの属性部分が格納される.要free
*/
int xml_parse_processing_tag(char* pp, char** tag_name, char** tag_attr)
{
int nn, mm;
char* pt;
*tag_name = NULL;
*tag_attr = NULL;
if (pp==NULL) return XML_PARSE_ERROR;
if (strncmp(pp, "", 2)) return XML_PARSE_ERROR;
pt = pp = pp + 2;
pt = skip_char(pt, " ?");
if (pt==NULL) return XML_PARSE_ERROR;
nn = mm = (int)(pt - pp);
if (mm==0) return XML_PARSE_ERROR;
nn += 2;
*tag_name = (char*)malloc((size_t)(mm + 1));
if (*tag_name==NULL) return XML_MEMORY_ERROR;
memcpy(*tag_name, pp, mm);
(*tag_name)[mm] = '\0';
if (isnot_xml_name((unsigned char*)(*tag_name))) return XML_PARSE_ERROR;
// for attribute
if (*pt==' ') {
pp = pt = pt + 1;
while (*pt==' ' || *pt==TAB || *pt==LF || *pt==CR) pt++;
nn += (int)(pt - pp) + 1;
pp = pt;
pt = skip_char(pt, "?");
if (pt==NULL) {
freeNull(*tag_name);
return XML_PARSE_ERROR;
}
mm = (int)(pt - pp);
if (mm>0) {
*tag_attr = (char*)malloc((size_t)(mm + 1));
if (*tag_attr==NULL) {
freeNull(*tag_name);
return XML_MEMORY_ERROR;
}
memcpy(*tag_attr, pp, mm);
(*tag_attr)[mm] = '\0';
nn += mm;
//print_message("ATTR --> %s %d\n", *tag_attr, (int)strlen(*tag_attr));
}
}
if (strncmp(pt, "?>", 2)) {
freeNull(*tag_name);
freeNull(*tag_attr);
return XML_PARSE_ERROR;
}
return nn + 2;
}
/**
int xml_parse_comment_tag(char* pp, char** comment)
機能:XMLのコメントタグを処理する.処理できるタグの型は
xml_parse_data_tag() に先立って適用させる必要がある.
引数:pp -- タグへのポインタ.'<' を指すポインタ.
*coment -- コメントを格納するポインタ.
戻り値:
return -- 0>: タグ全体の長さ.0 が返ることは無い.
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*commnet -- コメント部分がそのまま格納される.要free
*/
int xml_parse_comment_tag(char* pp, char** comment)
{
int nn, mm;
char* pt;
*comment = NULL;
if (pp==NULL) return XML_PARSE_ERROR;
if (strncmp(pp, "", 3)) return XML_PARSE_ERROR;
nn = mm = (int)(pt - pp);
if (mm==0) return XML_PARSE_ERROR;
nn += 4;
*comment = (char*)malloc((size_t)(mm+1));
if (*comment==NULL) return XML_MEMORY_ERROR;
memcpy(*comment, pp, mm);
(*comment)[mm] = '\0';
//print_message("COMMENT-> %s %d\n", *comment, (int)strlen(*comment));
return nn + 3;
}
/**
int xml_parse_data_tag(char* pp, char** data)
機能:XMLのデータタグ(その他エレメントタグなど)を処理する.
処理できるタグの型は
データ部分は解釈せずに,そのまま dataに格納される.
引数:pp -- タグへのポインタ.'<' を指すポインタ.
*data -- データ部分を格納するポインタ.
戻り値:
return -- 0>: タグ全体の長さ.0 が返ることは無い.
XML_PARSE_ERROR: パースエラー.
XML_MEMORY_ERROR: メモリエラー
*data -- データ部分がそのまま格納される.要free
*/
int xml_parse_data_tag(char* pp, char** data)
{
int nn, mm;
char* pt;
*data = NULL;
if (pp==NULL) return XML_PARSE_ERROR;
if (strncmp(pp, "");
if (pt==NULL) return XML_PARSE_ERROR;
nn = mm = (int)(pt - pp);
if (mm==0) return XML_PARSE_ERROR;
nn += 2;
*data = (char*)malloc((size_t)(mm+1));
if (*data==NULL) return XML_MEMORY_ERROR;
memcpy(*data, pp, mm);
(*data)[mm] = '\0';
//print_message("DATA ---> %s %d\n", *data, (int)strlen(*data));
return nn + 1;
}
/**
int isnot_xml_name(char* pp)
機能:XML名として不適切かどうかを大まかに判断する
かなりいい加減なので,FALSEだからといって,厳密にXML名として適切であるとは限らない
引数:pp -- 検査する XML名へのポインタ
戻り値:TRUE -- XML名として不適切
FALSE -- XML名として適切かもしれない
*/
int isnot_xml_name(unsigned char* pp)
{
if (pp==NULL) return TRUE;
if (*pp=='\0') return TRUE;
while (*pp!='\0') {
if (*pp<=0x2c) return TRUE; // !"#$%&'()*+,
if (*pp==0x2f) return TRUE; // /
if (*pp>=0x3b && *pp<=0x40) return TRUE; // ;<=>?@
if (*pp>=0x5b && *pp<=0x5e) return TRUE; // [\]^
if (*pp==0x60) return TRUE; // `
if (*pp>=0x7b && *pp<=0x7f) return TRUE; // {|}~DEL
pp++;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tools
//
/**
void close_xml(tXML* pp)
機能: パースエラーを起こしたツリーを強制的に正常化する.
引数: pp -- 正常化するツリーへのポインタ.
戻り値: なし.
*/
void close_xml(tXML* pp)
{
if (pp!=NULL) {
// アンカー
if (pp->ldat.id==XML_ANCHOR_TAG) {
pp->state = XML_PARSED;
pp->depth = 0;
if (pp->next!=NULL) {
pp->next->depth = 1;
adjust_tTree_depth(pp->next);
close_xml(pp->next);
}
return;
}
while(pp->esis!=NULL) pp = pp->esis;
do {
if (pp->state!=XML_TAG_EMPTY) pp->state = XML_TAG_ENDED;
if (pp->ldat.lst!=NULL) {
if ((pp->ldat.lst)->state!=XML_TAG_EMPTY) (pp->ldat.lst)->state = XML_TAG_ENDED;
}
if (pp->next!=NULL) close_xml(pp->next);
pp = pp->ysis;
} while(pp!=NULL);
}
return;
}
/**
void print_xml(FILE* fp, tXML* pp, int mode)
機能: XMLの表示.
引数: fp -- 出力するファイルへのポインタ.NULLの場合は stderr
pp -- 表示を開始するXMLタグへのポインタ.
mode -- XML_ONELINE_FORMAT, XML_CRLF_FORMAT, XML_INDENT_FORMAT
戻り値: なし.
*/
void print_xml(FILE* fp, tXML* pp, int mode)
{
if (fp==NULL) fp = stderr;
if (pp!=NULL) {
Buffer buf = xml_inverse_parse(pp, mode);
if (buf.buf!=NULL) {
fprintf(fp, "%s", buf.buf);
free_Buffer(&buf);
}
else fprintf(fp, "(XML is NULL)\n");
}
else {
fprintf(fp, "(XML is NULL)\n");
}
fflush(fp);
return;
}
/**
void print_xml_tree(FILE* fp, tXML* pp, char* space)
機能: XMLツリーをそのままツリー表示する.デバッグ用.
ポインタ pp以降の全てのタグのキー部のバッファを標準エラー出力に表示する.
表示:入れ子の深さ,ID, ノード状態, タグ名(タグ値),タグ属性の個数
引数: fp -- 出力するファイルへのポインタ.NULLの場合は stderr
pp -- 表示を開始するノードへのポインタ.
space -- 出力の書式を揃えるための空白(インデント)を指定する.
戻り値: なし.
*/
/*
void print_xml_tree(FILE* fp, tXML* pp, char* space)
{
int i;
if (fp==NULL) fp = stderr;
if (pp!=NULL) {
for(i=1; idepth; i++) fprintf(fp, space);
for(i=1; idepth-1; i++) fprintf(fp, " "); // for " -> "
if (pp->ldat.id==XML_ANCHOR_TAG) pp = pp->next;
if (pp!=NULL) {
print_sister_xml_tree_rcsv(fp, pp, space);
}
else {
fprintf(fp, "(XML is ANCHOR only)\n");
}
}
else {
fprintf(fp, "(XML is NULL)\n");
}
fflush(fp);
return;
}
*/
void print_xml_tree(FILE* fp, tXML* pp, char* space)
{
int i;
if (fp==NULL) fp = stderr;
if (pp!=NULL) {
for(i=1; idepth; i++) fprintf(fp, space);
for(i=1; idepth-1; i++) fprintf(fp, " "); // for " -> "
if (pp->ldat.id==XML_ANCHOR_TAG) pp = pp->next;
if (pp!=NULL) {
tList_data ld = pp->ldat;
fprintf(fp, "%d: %d [%d] %s (0)", pp->depth, ld.id, pp->state, ld.key.buf);
//if (pp->next!=NULL) print_sister_xml_tree(fp, pp->next, space);
//else fprintf(fp, "\n");
print_sister_xml_tree(fp, pp, space);
}
else {
fprintf(fp, "(XML is ANCHOR only)\n");
}
}
else {
fprintf(fp, "(XML is NULL)\n");
}
fflush(fp);
return;
}
/**
void print_sister_xml_tree(FILE* fp, tXML* pp, char* space)
}
else {
fprintf(fp, "(XML is ANCHOR only)\n");
}
}
else {
fprintf(fp, "(XML is NULL)\n");
}
fflush(fp);
return;
}
*/
/**
void print_sister_xml_tree(FILE* fp, tXML* pp, char* space)
機能: XMLツリーの表示.ppの姉妹ノードも出力する.
ポインタ pp以降の全てのノードのキー部のバッファを標準エラー出力に表示する.
表示:入れ子の深さ,ID, ノード状態, タグ名(タグ値),タグ属性の個数
引数: fp -- 出力するファイルへのポインタ.NULLの場合は stderr
pp -- 表示を開始するノードへのポインタ.(姉妹ノードも出力する)
space -- 出力の書式を揃えるための空白(インデント)を指定する.
戻り値: なし.
*/
void print_sister_xml_tree(FILE* fp, tXML* pp, char* space)
{
int i;
if (pp!=NULL) {
for(i=1; idepth; i++) fprintf(fp, space);
for(i=1; idepth-1; i++) fprintf(fp, " "); // for " -> "
}
print_sister_xml_tree_rcsv(fp, pp, space);
}
/**
void print_sister_xml_tree_rcsv(FILE* fp, tXML* pp, char* space)
機能:print_sister_xml_tree() の再帰用関数
*/
void print_sister_xml_tree_rcsv(FILE* fp, tXML* pp, char* space)
{
if (fp==NULL) fp = stderr;
if (pp!=NULL) {
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
}
while(pp->esis!=NULL) pp = pp->esis;
do {
int i;
tList_data ld = pp->ldat;
if (pp->depth>1) fprintf(fp, " -> ");
i = count_tList((tList*)ld.lst);
fprintf(fp, "%d: %d [%d] %s (%d)", pp->depth, ld.id, pp->state, ld.key.buf, i);
if (pp->next!=NULL) print_sister_xml_tree_rcsv(fp, pp->next, space);
else fprintf(fp, "\n");
pp = pp->ysis;
if (pp!=NULL) {
for(i=1; idepth; i++) fprintf(fp, space);
for(i=1; idepth-1; i++) fprintf(fp, " "); // for " -> "
}
} while(pp!=NULL);
}
else {
fprintf(fp, "(XML is NULL)\n");
}
fflush(fp);
return;
}
///////////////////////////////////////////////////////////////////////////////////////
//
// Operation
//
/**
tXML* add_xml_tag(tXML* xml, char* name)
機能:XMLツリーのxml の直下に開始タグを挿入する.
*/
tXML* add_xml_tag(tXML* xml, char* name)
{
tList* pp;
if (xml==NULL || name==NULL) return NULL;
pp = add_tTree_node_bystr(xml, XML_TAG_NAME, 0, name, NULL, NULL, 0);
pp->state = XML_TAG_STARTED;
if (pp->prev!=NULL) pp->prev->ldat.lv++;
return pp;
}
/**
tXML* add_xml_content(tXML* xml, char* content)
機能:XMLツリーのxml の直下にコンテントを挿入する.
xmlがタグ名ノードでなければエラー(NULLが返る)
*/
tXML* add_xml_content(tXML* xml, char* content)
{
tList* pp;
if (xml==NULL || content==NULL) return NULL;
if (xml->ldat.id!=XML_TAG_NAME) return NULL;
pp = add_tTree_node_bystr(xml, XML_TAG_CONTENT, 0, content, NULL, NULL, 0);
pp->state = XML_TAG_ENDED;
if (pp->prev!=NULL) pp->prev->ldat.lv++;
return pp;
}
/**
tXML* get_xml_tag(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のノードへのポインタを返す.
また,pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_NODE となっているタグは比較されない
返ってきた tXML* は free してはいけない.
引数:pp -- 検索対象のツリー
pt -- 検索するパターン
戻り値:ptの最後のタグに対応するタグへのポインタ.freeしてはいけない.
----------------------------------------------------------------
例: pp pt
A --> B --> M C --> M --> Y
--> C --> M --> X
--> Y --> Z
--> N
の場合,ppの Yへのポインタが返る.
*/
tXML* get_xml_tag(tXML* pp, tXML* pt)
{
int fnd;
tXML* tt;
tXML* pm;
if (pp==NULL || pt==NULL) return NULL;
pm = pp;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return NULL;
}
if (pt->ldat.id==XML_ANCHOR_TAG) {
if (pt->next!=NULL) pt = pt->next;
else return NULL;
}
tt = find_xml_end(pt);
if (tt==NULL) return FALSE;
while(pp->esis!=NULL) pp = pp->esis;
fnd = find_match_xml(pp, pt);
if (fnd) tt = tt->altp;
else tt = NULL;
clear_tTree_ctrl(pm);
return tt;
}
/**
int set_xml_tag(tXML* pp, tXML* pt, char* name)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のノードにタグ名をコピーする.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっている
ノードは比較されない.
引数:pp -- 対象のXMLツリー
pt -- 検索パターン
name -- ptの最後のタグに対応するタグにコピーするタグ名.
戻り値:TRUE : 設定するタグノードを見つけた.正常に設定れたかどうかは不明.
FALSE: 設定するタグノードを見つけられなかった.
*/
int set_xml_tag(tXML* pp, tXML* pt, char* name)
{
tXML* tt;
if (pp==NULL || pt==NULL || name==NULL) return FALSE;
tt = get_xml_tag(pp, pt);
if (tt==NULL) return FALSE;
copy_s2Buffer(name, &(tt->ldat.key));
return TRUE;
}
/**
int set_xml_end_tag(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のノードに ptの最後のタグの値(含む属性)をコピーする.
ただし,ptの最後のノードに関しては比較されない(コピー用だから).
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
コピーを行うのは ptの最後のノードのみである.
コピーする属性は ldat.id, ldat.lv, ldat.sz, ldat.key, ldat.val, ldat.ptr, ldat.lst
ldat.val, ldat.ptr, ldat.lst については,ptで値が設定されていなければ,置き換えを行わない.
引数:pp -- 対象のXMLツリー
pt -- 検索パターン
戻り値:TRUE : 設定する枝を見つけた.正常に設定れたかどうかは不明.
FALSE: 設定する枝を見つけられなかった.
*/
int set_xml_end_tag(tXML* pp, tXML* pt)
{
int ret;
tXML* tt;
tXML* pm;
if (pp==NULL || pt==NULL) return FALSE;
pm = pp;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return FALSE;
}
if (pt->ldat.id==XML_ANCHOR_TAG) {
if (pt->next!=NULL) pt = pt->next;
else return FALSE;
}
tt = find_xml_end(pt);
if (tt==NULL) return FALSE;
tt->ctrl = TREE_NOCMP_COPY_NODE; // 比べない.最後にコピー.
while(pp->esis!=NULL) pp = pp->esis;
ret = find_match_xml(pp, pt);
if (ret) {
copy_tTree_byctrl(pt);
adjust_tTree_depth(pp);
}
clear_tTree_ctrl(pm);
return ret;
}
/**
tXML* get_xml_content(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のタグのコンテントへのポインタを返す.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
返ってきた tXML* は free してはいけない.
引数:pp -- 検索対象のツリー
pt -- 検索するパターン
戻り値:ptの最後のタグの次のタグに対応するコンテントへのポインタ.freeしてはいけない.
----------------------------------------------------------------
例: pp pt
A --> B --> M C --> M --> Y
--> C --> M --> X
--> Y --> Z
--> N
の場合,Z へのポインタが返る.
*/
tXML* get_xml_content(tXML* pp, tXML* pt)
{
int fnd;
tXML* tt = NULL;
tXML* pm;
tXML* dm;
if (pp==NULL || pt==NULL) return NULL;
pm = pp;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return NULL;
}
if (pt->ldat.id==XML_ANCHOR_TAG) {
if (pt->next!=NULL) pt = pt->next;
else return NULL;
}
tt = find_xml_end(pt);
if (tt==NULL) return NULL;
dm = add_xml_content(tt, "DUMMY");
dm->ctrl = TREE_NOCMP_NODE;
while(pp->esis!=NULL) pp = pp->esis;
fnd = find_match_xml(pp, pt);
if (fnd) tt = dm->altp;
else tt = NULL;
del_xml(&dm);
clear_tTree_ctrl(pm);
return tt;
}
/**
int set_xml_content(tXML* pp, tXML* pt, char* content)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のタグのコンテントを contentで置き換える.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
引数:pp -- 対象のXMLツリー
pt -- 検索パターン
val -- ptの最後のタグに対応するタグにコピーするタグ値.
戻り値:TRUE : 設定する枝を見つけた.正常に設定れたかどうかは不明.
FALSE: 設定する枝を見つけられなかった.
*/
int set_xml_content(tXML* pp, tXML* pt, char* content)
{
tXML* tt;
if (pp==NULL || pt==NULL || content==NULL) return FALSE;
tt = get_xml_content(pp, pt);
if (tt==NULL) return FALSE;
copy_s2Buffer(content, &(tt->ldat.key));
return TRUE;
}
/**
tList* get_xml_attr(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のノードのタグ属性値を返す.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
引数:pp -- 検索対象のツリー
pt -- 検索するパターン
戻り値:ptの最後のタグ対応にする,ppのタグの属性値
*/
tList* get_xml_attr(tXML* pp, tXML* pt)
{
tList* lp = NULL;
tXML* tt;
if (pp==NULL || pt==NULL) return NULL;
tt = get_xml_tag(pp, pt);
if (tt!=NULL) lp = tt->ldat.lst;
return lp;
}
/**
int set_xml_attr(tXML* pp, tXML* pt, tList* at)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに最初に一致した枝の,
最後のノードにタグの属性として atの値をコピーする.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
引数:pp -- 操作対象のツリー
pt -- 検索パターン
at -- 設定する属性の格納されたリスト.ldat.keyに属性名,ldat.valに属性値("'付き)
戻り値:TRUE : 設定する枝を見つけた.正常に設置されたかどうかは不明.
FALSE: 設定する枝を見つけられなかった.
*/
int set_xml_attr(tXML* pp, tXML* pt, tList* at)
{
tXML* tt;
if (pp==NULL || pt==NULL || at==NULL) return FALSE;
tt = get_xml_tag(pp, pt);
if (tt!=NULL) {
del_all_tList(&(tt->ldat.lst));
tt->ldat.lst = dup_tList(at);
}
else return FALSE;
return TRUE;
}
/**
char* get_first_tag_name(tXML* xml)
機能:XMLツリーの最初のタグの名前を返す.
引数:xml -- XMLツリー
戻り値:XMLツリーの最初のタグの名前.freeしてはいけない.
*/
char* get_first_tag_name(tXML* xml)
{
char* tagname = NULL;
if (xml==NULL) return NULL;
tList* lp = xml;
if (lp->ldat.id==XML_ANCHOR_TAG) lp = lp->next;
while (lp!=NULL) {
if (lp->ldat.id==XML_TAG_NAME) {
if (lp->ldat.key.buf!=NULL) {
tagname = (char*)lp->ldat.key.buf;
break;
}
}
lp = lp->ysis;
}
return tagname;
}
/**
int replace_xml_content(tXML* pp, tXML* pt, char* src, char* dst)
*/
int replace_xml_content(tXML* pp, tXML* pt, char* src, char* dst)
{
tXML* tt;
Buffer tg;
if (pp==NULL || pt==NULL || src==NULL || dst==NULL) return FALSE;
tt = get_xml_content(pp, pt);
if (tt==NULL) return FALSE;
tg = replace_sBuffer_bystr(tt->ldat.key, src, dst);
if (tg.buf==NULL) return FALSE;
free_Buffer(&(tt->ldat.key));
tt->ldat.key = tg;
return TRUE;
}
/**
tXML* find_match_xml_end_tag(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptの最後のタグに対応する
pp内のノードへのポインタを返す.ノードは タグ名,コンテントのどちらでも可.
引数:pp -- 検索対象のXML
pt -- 検索パターンの文字列.
戻り値:strの最後のノードに対応する pp内のノード.
*/
tXML* find_match_xml_end_tag(tXML* pp, tXML* pt)
{
int ret;
tXML* tt = NULL;
tXML* pm;
if (pp==NULL || pt==NULL) return NULL;
pm = pp;
ret = find_match_tTree(pp, pt);
if (ret) {
tt = find_xml_end(pt);
if (tt!=NULL) {
tt = tt->altp;
}
}
clear_tTree_ctrl(pm);
return tt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
tXML* get_xml_tag(tXML* pp, tXML* pt)
tXML* set_xml_tag(tXML* pp, tXML* pt, char* val)
int set_xml_end_tag(tXML* pp, tXML* pt)
tXML* get_xml_content(tXML* pp, tXML* pt)
int set_xml_content(tXML* pp, tXML* pt, char* val)
tList* get_xml_attr(tXML* pp, tXML* pt)
int set_xml_attr(tXML* pp, tXML* pt, tList* at)
int replace_xml_content(tXML*pp, tXML* pt, char* src, char* dst)
の _bystr バージョン
*/
tXML* get_xml_tag_bystr(tXML* pp, char* str)
{
tXML* tx;
tXML* tt;
if (pp==NULL || str==NULL) return FALSE;
tx = xml_parse(str);
tt = get_xml_tag(pp, tx);
del_xml(&tx);
return tt;
}
int set_xml_tag_bystr(tXML* pp, char* str, char* val)
{
tXML* tx;
int rt;
if (pp==NULL || str==NULL || val==NULL) return FALSE;
tx = xml_parse(str);
rt = set_xml_tag(pp, tx, val);
del_xml(&tx);
return rt;
}
int set_xml_end_tag_bystr(tXML* pp, char* str)
{
tXML* tx;
int rt;
if (pp==NULL || str==NULL) return FALSE;
tx = xml_parse(str);
rt = set_xml_end_tag(pp, tx);
del_xml(&tx);
return rt;
}
tXML* get_xml_content_bystr(tXML* pp, char* str)
{
tXML* tx;
tXML* tt;
if (pp==NULL || str==NULL) return FALSE;
tx = xml_parse(str);
tt = get_xml_content(pp, tx);
del_xml(&tx);
return tt;
}
int set_xml_content_bystr(tXML* pp, char* str, char* val)
{
tXML* tx;
int rt;
if (pp==NULL || str==NULL || val==NULL) return FALSE;
tx = xml_parse(str);
rt = set_xml_content(pp, tx, val);
del_xml(&tx);
return rt;
}
tList* get_xml_attr_bystr(tXML* pp, char* str)
{
tXML* tx;
tList* tt;
if (pp==NULL || str==NULL) return FALSE;
tx = xml_parse(str);
tt = get_xml_attr(pp, tx);
del_xml(&tx);
return tt;
}
int set_xml_attr_bystr(tXML* pp, char* str, tList* at)
{
tXML* tx;
int rt;
if (pp==NULL || str==NULL || at==NULL) return FALSE;
tx = xml_parse(str);
rt = set_xml_attr(pp, tx, at);
del_xml(&tx);
return rt;
}
int replace_xml_content_bystr(tXML*pp, char* str, char* src, char* dst)
{
tXML* tx;
int rt;
if (pp==NULL || src==NULL || src==NULL || dst==NULL) return FALSE;
tx = xml_parse(str);
rt = replace_xml_content(pp, tx, src, dst);
del_xml(&tx);
return rt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
tList* get_xml_tag_list(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに一致した枝の,最後のノードへの
ポインタをリストに格納して返す.ポインタはリストの altpに格納される.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
引数:pp -- 検索対象のツリー
pt -- 検索するパターン
戻り値:該当ノードへのポインタ情報(altp)を含んだリストへのポインタ
*/
tList* get_xml_tag_list(tXML* pp, tXML* pt)
{
tList* lp;
if (pp==NULL || pt==NULL) return NULL;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return NULL;
}
if (pt->ldat.id==XML_ANCHOR_TAG) {
if (pt->next!=NULL) pt = pt->next;
else return NULL;
}
lp = find_match_xml_endlist(pp, pt);
return lp;
}
/**
tList* get_xml_content_list(tXML* pp, tXML* pt)
機能:XMLツリー pp内で XMLツリー ptと同じパターンの枝を探し,ptに一致した枝の,最後のタグの
コンテントへのポインタをリストに格納して返す.ポインタはリストの altpに格納される.
pt の中で ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE となっているノードは
比較されない.これらのノードは必ず一致する.
引数:pp -- 検索対象のツリー
pt -- 検索するパターン
戻り値:該当ノードへのポインタ情報(altp)を含んだリストへのポインタ
*/
tList* get_xml_content_list(tXML* pp, tXML* pt)
{
tList* lp;
tList* dm;
if (pp==NULL || pt==NULL) return NULL;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return NULL;
}
if (pt->ldat.id==XML_ANCHOR_TAG) {
if (pt->next!=NULL) pt = pt->next;
else return NULL;
}
dm = find_xml_end(pt);
if (dm==NULL) return NULL;
dm = add_xml_content(dm, "DUMMY");
dm->ctrl = TREE_NOCMP_NODE;
lp = find_match_xml_endlist(pp, pt);
del_xml(&dm);
return lp;
}
/**
int set_xml_content_list(tXML* pp, tXML* pt, char* content)
機能:get_xml_content_list() で検出したコンテントを, content で置き換える.
引数:pp -- 対象のXMLツリー
pt -- 検索パターン
content -- 書き換えのタグ値
戻り値:書き換えたノードの個数
*/
int set_xml_content_list(tXML* pp, tXML* pt, char* content)
{
int num = 0;
tList* lt;
tList* lp;
if (pp==NULL || pt==NULL || content==NULL) return 0;
lp = lt = get_xml_content_list(pp, pt);
if (lt==NULL) return 0;
while (lt!=NULL) {
if (lt->altp!=NULL) {
copy_s2Buffer(content, &(lt->altp->ldat.key));
num++;
}
lt = lt->next;
}
del_tList(&lp);
return num;
}
/**
tList* get_xml_tag_list_bystr(tXML* pp, char* str)
*/
tList* get_xml_tag_list_bystr(tXML* pp, char* str)
{
tXML* tx;
tList* tt;
if (pp==NULL || str==NULL) return NULL;
tx = xml_parse(str);
tt = get_xml_tag_list(pp, tx);
del_xml(&tx);
return tt;
}
/**
tList* get_xml_conetnt_list_bystr(tXML* pp, char* str)
*/
tList* get_xml_content_list_bystr(tXML* pp, char* str)
{
tXML* tx;
tList* tt;
if (pp==NULL || str==NULL) return NULL;
tx = xml_parse(str);
tt = get_xml_content_list(pp, tx);
del_xml(&tx);
return tt;
}
/**
int set_xml_content_list_bystr(tXML* pp, tXML* pt, char* content)
*/
int set_xml_content_list_bystr(tXML* pp, char* str, char* content)
{
tXML* tx;
int rt;
if (pp==NULL || str==NULL || content==NULL) return 0;
tx = xml_parse(str);
rt = set_xml_content_list(pp, tx, content);
del_xml(&tx);
return rt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
tXML* dup_merge_xml(tXML* pp, tXML* tp)
機能:XMLツリー ppの直下にXMLツリー tpを複製する.
引数:pp -- 複製されたツリーのトップとなるノード
tp -- 複製するツリー
戻り値:複製された XMLツリーへのポインタ.
pp がNULLでない場合は pp
pp がNULLの場合は,tpを複製したツリーのトップ.
*/
tXML* dup_merge_xml(tXML* pp, tXML* tp)
{
tXML* pt;
if (tp==NULL) return pp;
if (tp->ldat.id==XML_ANCHOR_TAG) {
if (tp->next!=NULL) tp = tp->next;
else return pp;
}
pp = dup_merge_tTree(pp, tp);
if (pp->ldat.id!=XML_ANCHOR_TAG) {
pt = new_tTree_node();
pt->ldat.id = XML_ANCHOR_TAG;
pt->depth = 0;
add_tTree(pt, pp);
close_xml(pt);
return pt;
}
return pp;
}
/**
tXML* del_xml(tXML** pp)
機能:指定したノード以下のXMLツリーを削除する.
引数:*pp -- 削除するツリーの先頭ノード
戻り値:削除したXMLツリーの親ノードへのポインタ.
*/
tXML* del_xml(tXML** pp)
{
tXML* pt;
if (pp==NULL || *pp==NULL) return NULL;
// 子ノードの削除
if ((*pp)->next!=NULL) del_sisters_children_xml(&((*pp)->next));
// 自分自身の削除
pt = (*pp)->prev;
if (pt!=NULL) {
if (pt->next==*pp) pt->next = (*pp)->ysis;
if (pt->back==*pp) pt->back = (*pp)->esis;
pt->num--;
}
if ((*pp)->ysis!=NULL) (*pp)->ysis->esis = (*pp)->esis;
if ((*pp)->esis!=NULL) (*pp)->esis->ysis = (*pp)->ysis;
free_tListdata(&((*pp)->ldat));
free(*pp);
*pp = NULL;
return pt;
}
/**
tXML* del_sister_xml(tXML** pp)
機能:指定したノード以下のXMLツリーを削除する.
引数:*pp -- 削除するツリーの先頭ノード
戻り値:削除したXMLツリーの親ノードへのポインタ.
*/
tXML* del_sister_xml(tXML** pp)
{
tXML* pt;
if (pp==NULL || *pp==NULL) return NULL;
pt = (*pp)->prev;
if (pt!=NULL) {
pt->next = NULL;
pt->back = NULL;
pt->num = 0;
}
del_sisters_children_xml(pp);
return pt;
}
/**
tXML* del_sisters_children_xml(tXML** pp)
機能:指定したノードの姉妹XMLツリー,子XMLツリーを削除する.
指定したXMLノードも削除する.
引数:*pp -- 削除するXMLツリーの起点ノード
戻り値:削除したツリー郡の親ノードへのポインタ.
注)再帰処理用.親ノードに対する処理は行わないので,別途呼び出し側で行うこと.
*/
tXML* del_sisters_children_xml(tXML** pp)
{
tXML* pm;
tXML* pt;
if (pp!=NULL || *pp==NULL) return NULL;
pt = (*pp)->prev;
pm = *pp;
while (pm->esis!=NULL) pm = pm->esis;
while (pm!=NULL) {
tXML* pw = pm;
if (pm->next!=NULL) del_sisters_children_xml(&(pm->next));
pm = pm->ysis;
free_tListdata(&(pw->ldat));
free(pw);
}
*pp = NULL;
return pt;
}
/**
void del_all_xml(tXML** pp)
機能: XMLツリーの全ノードの削除.ポインタ ppのノードを含むXMLツリー全体を削除する.
pp はツリー中であれば,どこを指していても良い.
引数: *pp -- 削除を開始するノードへのポインタ.
ツリー中であれば,どこを指していても良い.
戻り値: なし.
*/
void del_all_xml(tXML** pp)
{
tXML* pm;
if (pp==NULL || *pp==NULL) return;
pm = *pp;
while (pm->prev!=NULL) pm = pm->prev;
del_xml(&pm);
*pp = NULL;
return;
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Inverse Parse
//
/**
Buffer xml_inverse_parse(tXML* pp, int mode)
機能:ppに格納された XMLデータを元の書式に戻して Bufferに格納する.xml_parse() の逆.
引数:pp -- XMLデータの格納されたツリーへのポインタ
mode -- 元のXMLへ戻す時の書式
XML_ONELINE_FORMAT: 改行なしの一行にする.
XML_CRLF_FORMAT : タグの終わりを CR(0x0d), LF(0x0a)で改行する.
XML_INDENT_FORMAT : 先頭にインデント(TAB)をつけ,タグごとに改行 CR LF (0x0d,0x0a)する.
XML_CRLF_FORMAT, XML_INDENT_FORMAT でタグ値がある場合は,値を囲むタグは改行しない.
戻り値:変換したXMLデータを格納した Buffer変数.
*/
Buffer xml_inverse_parse(tXML* pp, int mode)
{
int cnt;
Buffer buf;
buf = init_Buffer();
if (pp==NULL) return buf;
if (pp->ldat.id==XML_ANCHOR_TAG) pp = pp->next;
if (pp==NULL) return buf;
cnt = count_tTree(pp);
buf = make_Buffer(cnt*LPASS);
if (buf.buf==NULL) return buf;
while (pp->esis!=NULL) pp = pp->esis;
xml_to_Buffer(pp, &buf, mode, pp->depth);
return buf;
}
/**
void xml_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
機能:xml_inverse_parse()用の補助関数.
ppに格納された XMLデータを元の書式に戻して Bufferに格納する.
引数:pp -- XMLデータの格納されたツリーへのポインタ
buf -- 変換したXMLデータを格納する Buffer変数.
mode -- 元のXMLへ戻す時の書式
XML_ONELINE_FORMAT: 改行なしの一行にする.
XML_CRLF_FORMAT : タグの終わりを CR(0x0d), LF(0x0a)で改行する.
XML_INDENT_FORMAT : 先頭にインデント(TAB)をつけ,タグごとに改行する.
indent -- インデントを付け始める深さ.modeが XML_INDENT_MODE のときのみ有効.
*/
void xml_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
{
do {
xml_opentag_to_Buffer(pp, buf, mode, indent);
if (pp->next!=NULL) xml_to_Buffer(pp->next, buf, mode, indent);
xml_closetag_to_Buffer(pp, buf, mode, indent);
pp = pp->ysis;
} while(pp!=NULL);
return;
}
/**
void xml_opentag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
機能:ツリー中のXMLのオープンタグのデータを元の書式に戻して Bufferに格納する.
引数:pp -- XMLデータの格納されたツリーのノードへのポインタ
buf -- 変換したXMLデータを格納した Buffer変数.
mode -- 元のXMLへ戻す時の書式
XML_ONELINE_FORMAT: 改行なしの一行にする.
XML_CRLF_FORMAT : タグの終わりを CR(0x0d), LF(0x0a)で改行する.
XML_INDENT_FORMAT : 先頭にインデント(TAB)をつけ,タグごとに改行する.
indent -- インデントを付け始める深さ.modeが XML_INDENT_MODE のときのみ有効.
*/
void xml_opentag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
{
int i;
// Name TAG
if (pp->ldat.id==XML_TAG_NAME) {
if (mode==XML_INDENT_FORMAT) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
cat_s2Buffer("<", buf);
cat_Buffer(&(pp->ldat.key), buf);
if (pp->ldat.lst!=NULL) {
xml_attr_to_Buffer(pp->ldat.lst, buf);
}
if (pp->next==NULL) {
if (pp->state==XML_TAG_EMPTY) cat_s2Buffer(" />", buf);
else {
cat_s2Buffer(">", buf);
cat_Buffer(&(pp->ldat.key), buf);
cat_s2Buffer(">", buf);
}
}
else {
cat_s2Buffer(">", buf);
}
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) {
if (pp->ldat.lv!=1 || pp->num!=1) cat_s2Buffer("\r\n", buf);
}
}
// Content
else if (pp->ldat.id==XML_TAG_CONTENT) {
if (mode==XML_INDENT_FORMAT) {
if (pp->prev!=NULL && (pp->prev->ldat.lv!=1 || pp->prev->num!=1)) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
}
cat_Buffer(&(pp->ldat.key), buf);
//if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) {
if (pp->prev!=NULL && (pp->prev->ldat.lv!=1 || pp->prev->num!=1)) cat_s2Buffer("\r\n", buf);
}
}
// xml TAG
else if (pp->ldat.id==XML_DOC_TAG) {
if (mode==XML_INDENT_FORMAT) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
cat_s2Buffer("", buf);
if (pp->ldat.key.buf!=NULL) {
cat_Buffer(&(pp->ldat.key), buf);
}
if (pp->ldat.lst!=NULL) {
xml_attr_to_Buffer(pp->ldat.lst, buf);
}
cat_s2Buffer("?>", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
}
// Comment TAG
else if (pp->ldat.id==XML_COMMENT_TAG) {
if (mode==XML_INDENT_FORMAT) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
cat_s2Buffer("", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
}
// Data TAG
else if (pp->ldat.id==XML_DATA_TAG) {
if (mode==XML_INDENT_FORMAT) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
cat_s2Buffer("ldat.val.buf!=NULL) {
cat_Buffer(&(pp->ldat.val), buf);
}
cat_s2Buffer(">", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
}
// Processing TAG
else if (pp->ldat.id==XML_PROCESS_TAG) {
if (mode==XML_INDENT_FORMAT) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
cat_s2Buffer("", buf);
if (pp->ldat.key.buf!=NULL) {
cat_Buffer(&(pp->ldat.key), buf);
}
if (pp->ldat.lst!=NULL) {
xml_attr_to_Buffer(pp->ldat.lst, buf);
}
cat_s2Buffer(" ?>", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
}
return;
}
/**
void xml_closetag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
機能:ツリー中のXMLのクローズタグのデータを元の書式に戻して Bufferに格納する.
引数:pp -- XMLデータの格納されたツリーのノードへのポインタ
buf -- 変換したXMLデータを格納した Buffer変数.
mode -- 元のXMLへ戻す時の書式
XML_ONELINE_FORMAT: 改行なしの一行にする.
XML_CRLF_FORMAT : タグの終わりを CR(0x0d), LF(0x0a)で改行する.
XML_INDENT_FORMAT : 先頭にインデント(TAB)をつけ,タグごとに改行する.
indent -- インデントを付け始める深さ.modeが XML_INDENT_MODE のときのみ有効.
*/
void xml_closetag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent)
{
int i;
if (pp->ldat.id==XML_TAG_NAME) {
if (pp->next!=NULL) {
if (mode==XML_INDENT_FORMAT) {
if (pp->ldat.lv!=1 || pp->num!=1) {
char* tabs = (char*)malloc(pp->depth-indent+1);
if (tabs!=NULL) {
for (i=indent; idepth; i++) tabs[i-indent] = '\t';
tabs[pp->depth-indent] = '\0';
cat_s2Buffer(tabs, buf);
free(tabs);
}
//for (i=indent; idepth; i++) cat_s2Buffer("\t", buf);
}
}
cat_s2Buffer("", buf);
cat_Buffer(&(pp->ldat.key), buf);
cat_s2Buffer(">", buf);
if (mode==XML_INDENT_FORMAT || mode==XML_CRLF_FORMAT) cat_s2Buffer("\r\n", buf);
}
}
return;
}
/**
void xml_attr_to_Buffer(tList* pp, Buffer* buf)
機能:リストに保存されたタグの属性をテキストへ戻す.
引数:pp -- 属性データが格納されたリストへのポインタ.
buf -- 変換した属性データを格納する Buffer変数.
*/
void xml_attr_to_Buffer(tList* pp, Buffer* buf)
{
while (pp!=NULL) {
cat_s2Buffer(" ", buf);
cat_Buffer(&(pp->ldat.key), buf);
if (pp->ldat.val.buf!=NULL) {
cat_s2Buffer("=", buf);
cat_Buffer(&(pp->ldat.val), buf);
}
pp = pp->next;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Search Function for XML
// tTree 用の関数とほぼ同じ
//
/**
int find_match_xml(tXML* pp, tXML* pt)
機能:ツリー pp内で ツリー ptと同じパターンの枝を探す,
同じパターンの探索では キー値のみを比較し,ノード値は比較しない.
ただし,pt->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする).
もし同じツリーパターンがある場合,trの各ノードの altpには,一番最初に見つかった対応する ppの各ノードへ
のポインタが格納される.
check_match_xml() との違い.
check_match_xml() では比べる枝の開始ノードはppに固定される.
find_match_xml() は pp内を移動しながら検索できる.
引数:pp -- 検索対象のツリー
pt -- 検索パターンのツリー
戻り値:TRUE: pp中に pt同じいツリーパターンが存在する.
ptの各ノードの altpには,一番最初に見つかった対応する ppの各ノードへのポインタが格納される.
FALSE: ppに同じツリーパターンは無い.この場合,ptのaltpの値は不定となる.
*/
int find_match_xml(tXML* pp, tXML* pt)
{
int ret;
tXML* pm;
pm = pp;
while(pp!=NULL) {
ret = check_match_xml(pp, pt);
if (ret) return TRUE;
if (pp->next!=NULL) {
ret = find_match_xml(pp->next, pt);
if (ret) {
clear_tTree_ctrl(pm);
return TRUE;
}
}
pp = pp->ysis;
}
return FALSE;
}
/**
tXML* find_match_xml_endlist(tXML* pp, tXML* pt)
機能:ツリー pp内で ツリー ptと同じパターンの枝を全て探して,その枝の最後のノードへの情報をリストにして返す.
該当ノードへのポインタは 返された各リストのaltp が保持している.
比較では キー値のみを比較し,ノード値は比較しない.
また,pt->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする).
引数:pp -- 検索対象のツリー
pt -- 検索パターンのツリー
戻り値:該当ノードへのポインタを保持するリスト.
*/
tXML* find_match_xml_endlist(tXML* pp, tXML* pt)
{
tXML* te;
tList* lp;
te = find_xml_end(pt);
while(pp->esis!=NULL) pp = pp->esis;
lp = find_match_xml_endlist_rcsv(pp, pt, te);
if (lp!=NULL) clear_tTree_ctrl(pp);
return lp;
}
/**
tList* find_match_xml_endlist_rcsv(tXML* pp, tXML* pt, tXML* te)
機能:find_match_xml_endlist() の補助関数
*/
tList* find_match_xml_endlist_rcsv(tXML* pp, tXML* pt, tXML* te)
{
tList* lt = NULL;
tList* lp = NULL;
while(pp!=NULL) {
int ret = check_match_xml(pp, pt);
if (ret && te->altp!=NULL) {
tList* lm = new_tList_node();
lm->altp = te->altp;
lt = insert_tList(lt, lm);
if (lp==NULL) lp = lt;
te->altp = NULL;
}
if (pp->next!=NULL) {
tList* lm = find_match_xml_endlist_rcsv(pp->next, pt, te);
if (lm!=NULL) {
lt = insert_tList(lt, lm);
if (lp==NULL) lp = lt;
clear_tTree_ctrl(pp->next);
}
}
if (!ret) pp = pp->ysis; // 見つかった場合はもう一度.見つからなかった場合へ次へ.
}
return lp;
}
/**
int check_match_xml(tXML* tp, tXML* tr)
機能:XMLツリー tpが XMLツリー trと同じかどうかを検査する.
tp のトップと tr のトップはキー値が一致している必要がある.一致していなければ,同じパターンは無しとする.
ただし,tr->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする).
一度見つけた tpの枝の最後のノードに対しては ctrlを TREE_ALREADY_FOUND_NODE を設定するので,続けてチェックする
場合などは ctrl をクリアする必要がある.
もし同じツリーパターンがある場合,trの各ノードの altpには,一番最初に見つかった
対応する tpの各ノードへのポインタが格納される.
引数:tp -- 検索対象のツリー
tr -- 検索パターンのツリー
戻り値:TRUE: tp中に trと同じいツリーパターンが存在する.
trの各ノードの altpには,一番最初に見つかった対応する tpの各ノードへのポインタが格納される.
FALSE: tpに同じツリーパターンは無い.この場合,trの altpの値は不定となる.
*/
int check_match_xml(tXML* tp, tXML* tr)
{
int ret;
tXML* te;
tXML* ts;
tXML* tt;
tXML* ta;
tXML* tb;
if (tp==NULL || tr==NULL) return FALSE;
te = find_tList_end(tr);
ts = tp;
while (ts!=NULL) {
tt = cmp_sisters_xml(ts, tr); // その階層で trと全て一致している部分があるかを確認
if (tt==NULL) return FALSE; // 一致していなければ,FALSE
ta = tt; // 比べられるツリー
tb = tr; // 比べるパターン
ret = TRUE;
while (tb!=NULL && ret) {
if (tb->next==NULL) ret = TRUE;
// ->ta, ->tb->tx: FALSE
else if (tb->next!=NULL && ta->next==NULL) ret = FALSE;
// ->ta->xa, ->tb->xb: xaとxbをチェック
else ret = check_match_xml(ta->next, tb->next);
ta = ta->ysis;
tb = tb->ysis;
}
if (ret) {
if (tr==te) tt->ctrl = TREE_ALREADY_FOUND_NODE;
return TRUE;
}
ts = tt->ysis;
}
return FALSE;
}
/**
tXML* cmp_sisters_xml(tXML* tp, tXML* tr)
機能:XMLノード tpの姉妹ノードが trの姉妹ノードと同じ XMLタグまたはコンテントであるかを比較する.
ただし,tr->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする).
また tp->ctrl が TREE_ALREADY_FOUND_NODE の場合は,常に一致しない.
もし同じノードパターンがある場合,trの各ノードの altpには対応する tpの各ノードへのポインタが格納される.
また tpの各ノードの ctrlには TREE_ALREADY_FOUND_NODE が設定される.
引数:tp -- 比べる姉妹ノードの長女ノード
tr -- 探す姉妹ノードパターンの長女ノード
戻り値:tp中で trと同じパターンが始まるノードへのポインタ.
trの各ノードの altpには対応する tpの各ノードへのポインタが格納される.
NULL: tpに同じ姉妹パターンは無い.
----------------------------------------------------------------
例: tp tr
--> A (1) --> A A, B, X は キー値(ldat.key.buf)
--> B (2) --> X
--> A (3)
--> X (4)
--> A (5)
--> X (6)
の場合,cmp_sisters_xml(tp, tr) は (3)へのポインタを返す.また trの Aノード
の altp には (3) へのポインタが,trの Xノードのaltpには(4)へのポインタが格納
される.最初に見つかったパターンのみ評価される.
*/
tXML* cmp_sisters_xml(tXML* tp, tXML* tr)
{
tXML* ta;
tXML* tb = NULL;
tXML* ts;
ts = tp;
while (ts!=NULL){
ta = ts;
tb = tr;
while (ta!=NULL && tb!=NULL) {
// 一致しない場合 break
if (ta->ctrl==TREE_ALREADY_FOUND_NODE) break;
if (tb->ctrl!=TREE_NOCMP_NODE && tb->ctrl!=TREE_NOCMP_COPY_NODE) {
if ((ta->ldat).key.buf!=NULL && (tb->ldat).key.buf!=NULL) {
if (ta->ldat.id!=tb->ldat.id || strcmp((char*)((ta->ldat).key.buf), (char*)((tb->ldat).key.buf))) break;
}
else break;
}
// ta と tb は一致
tb->altp = ta;
ta = ta->ysis;
tb = tb->ysis;
}
// ts と tr は完全に一致
if (tb==NULL) return ts;
ts = ts->ysis;
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// Simple Tag Functions (単純な構造のタグの操作)
//
/**
Buffer get_tag_content(tXML* tp, char* name, int no)
機能:tp 中のXMLデータから no番目のタグ tag_content のtag_contentのコピーを得る.
タグが複数のコンテントを持つ場合は,最初のコンテントのみを返す.
*/
Buffer get_tag_content(tXML* tp, char* name, int no)
{
Buffer content;
tXML* tt;
content = init_Buffer();
if (tp==NULL || name==NULL) return content;
if (no<=0) no = 1;
tt = strncmp_tTree(tp, name, 0, no);
if (tt!=NULL) {
if (tt->next!=NULL) {
tt = tt->next;
while (tt!=NULL && tt->ldat.id!=XML_TAG_CONTENT) tt = tt->ysis;
if (tt==NULL) return content;
content = dup_Buffer(tt->ldat.key);
}
}
return content;
}
/**
int get_tag_integer(tXML* tp, char* name, int no)
機能:tp中のXMLデータから no番目のタグ tag_content(整数) の tag_content(整数)を得る.
*/
int get_tag_integer(tXML* tp, char* name, int no)
{
int ret;
Buffer content;
content = get_tag_content(tp, name, no);
if (content.buf==NULL) ret = 0;
else ret = atoi((const char*)content.buf);
free_Buffer(&content);
return ret;
}
/**
int return_exist_tag(tXML* tp, char* name, int no, Buffer* content)
機能:bufの中に タグ content が存在するかどうかチェックする.
存在する場合はそのタグのコンテントのコピーを content に格納し,TRUE を返す.
*/
int return_exist_tag(tXML* tp, char* name, int no, Buffer* content)
{
Buffer buf;
buf = get_tag_content(tp, name, no);
if (buf.buf==NULL) return FALSE;
if (content!=NULL) *content = buf;
return TRUE;
}
/**
int replace_all_tag_integer(tXML* tp, char* name, int src, int dst)
機能:XMLツリー pp内で タグ名が nameである全てのタグのコンテント(整数)を,srcから dstに書き換える.
引数:tp -- 置換対象のツリー
name -- 置き換えを行うタグのタグ名
src -- 置換対象のタグのコンテント(整数)
dst -- 置換後のタグのコンテント(整数)
戻り値:置き換えたノードの数
*/
int replace_all_tag_integer(tXML* tp, char* name, int src, int dst)
{
int n;
char nums[20], numd[20];
snprintf(nums, 10, "%d", src);
snprintf(numd, 10, "%d", dst);
n = replace_all_tag_contents(tp, name, nums, numd);
return n;
}
/**
int replace_all_tag_contents(tXML* pp, char* name, char* src, char* dst)
機能:XMLツリー pp内で タグ名が nameである全てのタグのコンテントを,srcから dstに書き換える.
一つのタグに複数のコンテントがある場合にも対応.
引数:tp -- 置換対象のツリー
name -- 置き換えを行うタグのタグ名.NULLの場合は全ての文字列.
src -- 置換対象のタグのコンテント(の一部でも可). NULL の場合は全ての文字列
dst -- 置換後のタグのコンテント
戻り値:置き換えたタグの数
*/
int replace_all_tag_contents(tXML* pp, char* name, char* src, char* dst)
{
int n;
if (pp==NULL || dst==NULL) return 0;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return 0;
}
while(pp->esis!=NULL) pp = pp->esis;
n = replace_all_tag_contents_rcsv(pp, name, src, dst);
return n;
}
/**
int replace_all_tag_contents_rcsv(tXML* pp, char* name, char* src, char* dst)
機能:replace_all_tag_content() の補助関数
*/
int replace_all_tag_contents_rcsv(tXML* pp, char* name, char* src, char* dst)
{
int n = 0;
while(pp!=NULL) {
if (pp->ldat.key.buf!=NULL && pp->ldat.id==XML_TAG_NAME && pp->ldat.lv>0) {
if (name==NULL || !strcmp(name, (const char*)(pp->ldat.key.buf))) {
tXML* tt = pp->next;
// 複数のコンテント
while (tt!=NULL) {
if (tt->ldat.id==XML_TAG_CONTENT) {
if (src==NULL) {
copy_s2Buffer(dst, &(tt->ldat.key));
n++;
}
else if (tt->ldat.key.buf!=NULL && strstr((const char*)tt->ldat.key.buf, src)!=NULL) {
Buffer buf = replace_sBuffer_bystr(tt->ldat.key, src, dst);
free_Buffer(&(tt->ldat.key));
tt->ldat.key = buf;
n++;
}
}
tt = tt->ysis;
}
}
}
if (pp->next!=NULL) n += replace_all_tag_contents_rcsv(pp->next, name, src, dst);
pp = pp->ysis;
}
return n;
}
/**
int replace_all_tag_byid(tXML* pp, char* src, char* dst, int id)
機能:XMLツリー pp内で タグの種別が idである全てのタグの内容を srcから dstに書き換える.
引数:tp -- 置換対象のツリー
src -- 置換対象のタグのコンテント(の一部でも可). NULL の場合は全ての文字列
dst -- 置換後のタグのコンテント
id -- 置き換え対象のノードのID.id<0 なら全てのノード
戻り値:置き換えたタグの数
*/
int replace_all_tag_byid(tXML* pp, char* src, char* dst, int id)
{
int n;
if (pp==NULL || dst==NULL) return 0;
if (pp->ldat.id==XML_ANCHOR_TAG) {
if (pp->next!=NULL) pp = pp->next;
else return 0;
}
while(pp->esis!=NULL) pp = pp->esis;
n = replace_all_tag_byid_rcsv(pp, src, dst, id);
return n;
}
/**
int replace_all_tag_byid_rcsv(tXML* pp, char* src, char* dst, int id)
機能:replace_all_tag_byid() の補助関数
*/
int replace_all_tag_byid_rcsv(tXML* pp, char* src, char* dst, int id)
{
int n = 0;
while(pp!=NULL) {
if (id<0 || pp->ldat.id==id) {
if (src==NULL) {
copy_s2Buffer(dst, &(pp->ldat.key));
n++;
}
else if (pp->ldat.key.buf!=NULL && strstr((const char*)pp->ldat.key.buf, src)!=NULL) {
Buffer buf = replace_sBuffer_bystr(pp->ldat.key, src, dst);
free_Buffer(&(pp->ldat.key));
pp->ldat.key = buf;
n++;
}
}
if (pp->next!=NULL) n += replace_all_tag_byid_rcsv(pp->next, src, dst, id);
pp = pp->ysis;
}
return n;
}