/* vi: set tabstop=4 paste nocindent noautoindent: */

#ifndef  __JBXL_TINY_XML_H_
#define  __JBXL_TINY_XML_H_


/**
	Tiny XML txml.h v1.0

	サブセット版　整形式XML 簡易パーサ ライブラリヘッダ

	全てのパターンのパース可能性を保障するものではありません
	複雑な XMLは（恐らく）パースできません．
		<?xml ... ?> 以外の <? ..... ?> と <! .....  > は処理しない（読み込みは行う）
		エンティティは処理しない．




--------------------
tXML:   (tXML は tList, tTree と同じもの)

１．タグデータ tXML：

	int	 	ldat.id		タグの種別．XML_ANCHOR_TAG, XML_TAG_NAME, XML_TAG_CONTENT, ..........
	int	 	ldat.lv		タグ値である子ノードの個数
	int	 	ldat.sz		未使用
	Buffer  ldat.key	タグ名またはタグ値
	Buffer  ldat.val	<! ... > の未処理データと <!-- ... -->のコメント情報を格納 
	void*	ldat.ptr	未使用 
	tXML*	ldat.lst	属性リストへのポインタ．ldat.lst->ldat.keyに属性名，ldat.lst->ldat.valに属性値("'付き)を格納

	tXML*	next		子タグ（長女）へのポインタ
	tXML*	prev		親タグへのポインタ
	tXML*	altp		その他へのポインタ（汎用） 
	tXML*	back		子タグ（末っ子）へのポインタ 
	tXML*	esis		前の姉妹（姉）タグへのポインタ
	tXML*	ysis		次の姉妹（妹）タグへのポインタ

	int		depth   	深さ					
	int		num	 		子ノードの数	
	int		ctrl		制御用
	int		state   	ノードの状態  XML_PARSED, XM_TAG_OPEND, XML_TAG_ENDED, XML_PARSE_ERROR, ....



２．パースしたXML情報を格納するツリー構造

  	<?xml version="1.0" ?><A><B><C>ABC</C><D />EFG</B><E /><!-- comment --></A> 

	の場合，次のようにパースされる．表示は ldat.key.buf (id)

  	NULL (XML_ANCHOR_TAG) -> xml (XML_DOC_TAG)
						  -> A (XML_TAG_NAME) -> B (XML_TAG_NAME) -> C (XML_TAG_NAME) -> ABC (XML_TAG_CONTENT)
                                                                  -> D (XML_TAG_NAME)
																  -> EFG (XML_TAG_CONTENT)
											  -> E (XML_TAG_NAME)
											  -> @COMMENT_TAG (XML_COMMENT_TAG) 	// ただしコメントの処理は暫定的


３．タグ（ノード）種別 (ldat.id)
		XML_ANCHOR_TAG			アンカータグ
		XML_TAG_NAME			タグネーム
		XML_TAG_CONTENT			タグの内容（コンテント）
		XML_DOC_TAG				<? xml... ?> タグ
		XML_COMMENT_TAG			コメントタグ
		XML_DATA_TAG			<! ... > タグ
		XML_PROCESS_TAG 		XML_DOC_TAG 以外の <? ... ?>タグ


４．状態 (state)
		XML_DEFAULT_SATE		ノードは，正常にパースされたかどうかの判定はまだ行われていない．
		XML_PARSED				アンカータグにのみ設定される．このXMLツリーは正常にパースされたことを示す．
		XML_TAG_STARTED			このノードはオープン状態にある． <tagname>
		XML_TAG_ENDED			このノードは正常にクローズした． </tagname>
		XML_TAG_EMPTY			このノードは空要素タグである <  />, <!--  -->, <!   >, <?   ?> の型
		XML_MULTI_ROOT			アンカータグにのみ設定される．このXMLツリーは２つ以上の独立したツリーを持つ

		XML_PARSE_ERROR			解釈エラー
		XML_SEQUENCE_ERROR		アンカーを越えてツリーを作ろうとした．
		XML_MEMORY_ERROR		メモリの確保エラー

*/






#include "tlist.h"


// タグ種別	(ldat.id)
#define  XML_ANCHOR_TAG				0
#define  XML_TAG_NAME				1
#define  XML_TAG_CONTENT			2
#define  XML_DOC_TAG				3
#define  XML_COMMENT_TAG			4
#define  XML_DATA_TAG				5
#define  XML_PROCESS_TAG			6


// タグ(ノード)の状態．エラーは 0以下にする．(state)
#define  XML_DEFAULT_STATE			0
#define  XML_PARSED					1	
#define  XML_TAG_STARTED			2
#define  XML_TAG_ENDED				3
#define  XML_TAG_EMPTY				4
#define  XML_MULTI_ROOT				9

#define  XML_PARSE_ERROR			-1
#define  XML_SEQUENCE_ERROR			-2
#define  XML_MEMORY_ERROR			-9


// XML Format
#define  XML_ONELINE_FORMAT			0
#define  XML_CRLF_FORMAT			1
#define  XML_INDENT_FORMAT			2


// 代用タグ名 (ldat.key.buf) 暫定的
#define  XML_COMMENT_TAG_KEY		"@COMMENT_TAG"
#define  XML_DATA_TAG_KEY			"@DATA_TAG"




typedef  struct _tList  tXML;



/////////////////////////////////////////////////////////////////////////////////////////////
//
// XML Functions
//

// Paser
tXML*	xml_parse(char* pp);
tXML*	xml_parse_file(char* pp);
tXML*	xml_parse_seq(tXML* xml, char* pp);
tXML*	xml_partial_parse(tXML* xml, char* pp, int skip);

int 	xml_parse_content(char* pp, char** content);
tList*	xml_parse_attr(char* pp);
int  	xml_parse_start_tag(char* pp, char** tag_name, char** tag_attr, int* tag_end);
int  	xml_parse_end_tag(char* pp, char** tag_name);
int  	xml_parse_processing_tag(char* pp, char** tag_name, char** tag_attr);
int  	xml_parse_comment_tag(char* pp, char** comment);
int  	xml_parse_data_tag(char* pp, char** data);

void 	close_xml(tXML* pp);
int	 	isnot_xml_name(unsigned char* pp);


// Operation
tXML* 	add_xml_tag(tXML* xml, char* name);
tXML* 	add_xml_content(tXML* xml, char* value);

tXML*	get_xml_tag(tXML* pp, tXML* pt);
int		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);

char*   get_first_tag_name(tXML* xml);

int		replace_xml_content(tXML*pp, tXML* pt, char* src, char* dst);
tXML*  	find_match_xml_end_tag(tXML* pp, tXML* pt);

#define find_xml_top(p)		find_tList_top(p)
#define find_xml_end(p)		find_tTree_end(p)

//
tXML*	get_xml_tag_bystr(tXML* pp, char* str);
int		set_xml_tag_bystr(tXML* pp, char* str, char* val);
int 	set_xml_end_tag_bystr(tXML* pp, char* str);

tXML*	get_xml_content_bystr(tXML* pp, char* str);
int 	set_xml_content_bystr(tXML* pp, char* str, char* val);
tList*	get_xml_attr_bystr(tXML* pp, char* str);
int		set_xml_attr_bystr(tXML* pp, char* pt, tList* at);


int		replace_xml_content_bystr(tXML*pp, char* str, char* src, char* dst);


// Operation for multi tags
tList*	get_xml_tag_list(tXML* pp, tXML* pt);
tList*	get_xml_content_list(tXML* pp, tXML* pt);
int		set_xml_content_list(tXML* pp, tXML* pt, char* content);

tList*	get_xml_tag_list_bystr(tXML* pp, char* str);
tList*	get_xml_content_list_bystr(tXML* pp, char* str);
int		set_xml_content_list_bystr(tXML* pp, char* str, char* content);


//
tXML*	dup_merge_xml(tXML* pp, tXML* tp);
void 	print_xml(FILE* fp, tXML* pp, int mode);
void 	print_xml_tree(FILE* fp, tXML* pp, char* space);
void 	print_sister_xml_tree(FILE* fp, tXML* pp, char* space);
void 	print_sister_xml_tree_rcsv(FILE* fp, tXML* pp, char* space);

tXML* 	del_xml(tXML** pp);
void  	del_all_xml(tXML** pp);
tXML* 	del_sister_xml(tXML** pp);
tXML*	del_sisters_children_xml(tXML** pp);


// 逆パース
Buffer	xml_inverse_parse(tXML* pp, int mode);
void	xml_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent);
void	xml_opentag_to_Buffer (tXML* pp, Buffer* buf, int mode, int indent);
void	xml_closetag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent);
void	xml_attr_to_Buffer(tList* pp, Buffer* buf);



///////////////////////////////////////////////////////////////////////////////////////////
// Search XML Tag (tTree用の関数とほぼ同じ)
int  	find_match_xml(tXML* pp, tXML* pt);
tXML*  	find_match_xml_endlist(tXML* pp, tXML* pt);
tList*  find_match_xml_endlist_rcsv(tXML* pp, tXML* pt, tXML* te);
int  	check_match_xml(tXML* tp, tXML* tr);
tXML*  	cmp_sisters_xml(tXML* tp, tXML* tr);




/////////////////////////////////////////////////////////////////////////////////////////////
//
// Simple Tag Funxtions.
//
int		get_tag_integer (tXML* tp, char* name, int no);
Buffer  get_tag_content (tXML* tp, char* name, int no);
int		return_exist_tag(tXML* tp, char* name, int no, Buffer* value);

int		replace_all_tag_integer (tXML* tp, char* name, int src, int dst);
int		replace_all_tag_contents(tXML* tp, char* name, char* src, char* dst);
int 	replace_all_tag_contents_rcsv(tXML* tp, char* name, char* src, char* dst);

int 	replace_all_tag_byid(tXML* tp, char* src, char* dst, int id);
int 	replace_all_tag_byid_rcsv(tXML* tp, char* src, char* dst, int id);



/**/


#endif
