MUSASHI C source: xmltree.c
0001: /*============================================================================*/
0002: /* 変更履歴 */
0003: /*----------------------------------------------------------------------------*/
0004: /* 1.0 : 新しいAPIに対応 */
0005: /*============================================================================*/
0006:
0007: #include <musashi.h>
0008: #include <stdio.h>
0009: #include <stdlib.h>
0010: #include <string.h>
0011: #include <libxml/parser.h>
0012: #include <libxml/parserInternals.h>
0013: #include <libxml/encoding.h>
0014: #include <iconv.h>
0015: #include <errno.h>
0016: #include <glob.h>
0017: #include <stdarg.h>
0018:
0019: #include <xmltreeHelp.h>
0020: struct mssComHelp comHelp={
0021: "xmltree", /* コマンド名 */
0022: "1.0", /* バージョン */
0023: HELPT, /* コマンドタイトル */
0024: HELPS, /* 要約 */
0025: HELPE, /* 利用例 */
0026: HELPR, /* 参照コマンド */
0027: HELPA, /* 作者情報 */
0028: HELPB, /* バグレポート情報 */
0029: HELPH /* ホームページ */
0030: };
0031:
0032: #define UNDEF 0
0033: #define MAX_NEST 32
0034: #define LOCAL_BUF 256
0035: #define EncMax MssFieldMaxLen /*iconvで使う出力用文字列長*/
0036:
0037: /*----------------------------------------------------------------------------*/
0038: /* 構造体 */
0039: /*----------------------------------------------------------------------------*/
0040: struct Node {
0041: char *element; /*要素文字列*/
0042: int emptyTagFlg;
0043: char **atts; /*属性リスト*/
0044: int attCnt;
0045: struct Node *parent;
0046: struct mssHash *children;
0047: };
0048:
0049: typedef struct _XmlState {
0050: int level;
0051: int crFlg;
0052: }XmlState;
0053:
0054: /*----------------------------------------------------------------------------*/
0055: /* グローバル変数 */
0056: /*----------------------------------------------------------------------------*/
0057: extern struct mssGlobalVariables mssGV;
0058: extern xmlParserCtxtPtr ctxt;
0059:
0060: static struct mssFPW *fpw; /*出力ファイル構造体*/
0061: static iconv_t *icid; /*iconv用 変換ハンドラ*/
0062: static char *inEnc=NULL; /*エンコーディング*/
0063: static char *inVer=NULL; /*バージョン*/
0064: static struct Node *currentNode;
0065: static struct Node *tree;
0066:
0067: /*============================================================================*/
0068: /* オプション宣言&定義 */
0069: /*============================================================================*/
0070: /*----------------------------------------------------------------------------*/
0071: /* 入力ファイル */
0072: /*----------------------------------------------------------------------------*/
0073: MssOptINF optINF={
0074: OINF, /* オプションタイプ */
0075: "i", /* キーワード(複数文字は不可) */
0076: 0, /* 0:オプション, 1:必須 */
0077: 1, /* 指定可能の最大ファイル数 */
0078: 0, /*1:file not foundのエラーで終了しない 0:する */
0079: INFT, /* このオプションのタイトル(Helpで表示) */
0080: INFC /* このオプションのコメント(Helpで表示) */
0081: };
0082:
0083: /*----------------------------------------------------------------------------*/
0084: /* 出力ファイル */
0085: /*----------------------------------------------------------------------------*/
0086: MssOptOTF optOTF={
0087: OOTF, /* オプションタイプ */
0088: "o", /* キーワード(複数文字は不可) */
0089: 0, /* 0:オプション, 1:必須 */
0090: OTFT, /* このオプションのタイトル(Helpで表示) */
0091: OTFC /* このオプションのコメント(Helpで表示) */
0092: };
0093:
0094: /*----------------------------------------------------------------------------*/
0095: /* 圧縮出力 */
0096: /*----------------------------------------------------------------------------*/
0097: MssOptFLG optZIP={
0098: OFLG, /* オプションタイプ */
0099: "z", /* キーワード(複数文字は不可) */
0100: 0, /* デフォルト(基本的には0) 常にonにしたいときは1にする */
0101: ZIPT, /* このオプションのタイトル(Helpで表示) */
0102: ZIPC /* このオプションのコメント(Helpで表示) */
0103: };
0104:
0105: /*----------------------------------------------------------------------------*/
0106: /* オプションをまとめる */
0107: /*----------------------------------------------------------------------------*/
0108: void *opt[]={&optINF,&optOTF,&optZIP,NULL};
0109:
0110: /*----------------------------------------------------------------------------*/
0111: /* ツリー構造の要素と属性を書き出し */
0112: /*----------------------------------------------------------------------------*/
0113: int Level=-1;
0114: void printTree(struct Node *node){
0115: struct mssHashNode *hnode;
0116: struct mssXmlTag *xmlTag;
0117: int i;
0118:
0119: if(node->element !=NULL){
0120: mssWriteXmlIndent(Level,fpw);
0121: xmlTag=mssInitXmlTag(node->element,NULL);
0122: if(node->atts!=NULL){
0123: for(i=0;;i++){
0124: if(*(node->atts+2*i+0)==NULL) break;
0125: if(*(node->atts+2*i+1)==NULL) break;
0126: mssAddXmlTagAttributeStr(xmlTag,*(node->atts+2*i),
0127: *(node->atts+2*i+1),NULL);
0128: }
0129: }
0130:
0131: if(node->emptyTagFlg){
0132: mssWriteXmlEmptyTag(xmlTag,icid,fpw);
0133: mssGV.outCnt++;
0134: mssWriteRet(fpw);
0135: return;
0136: }else{
0137: mssWriteXmlStartTag(xmlTag,icid,fpw);
0138: mssGV.outCnt++;
0139: }
0140: mssFreeXmlTag(xmlTag);
0141:
0142: if(node->children->cnt!=0){
0143: mssWriteRet(fpw);
0144: }
0145: }
0146:
0147: if(node->children==NULL) return;
0148:
0149: for(i=0; i<node->children->hashVal; i++){
0150: if( NULL != (hnode=*(node->children->node+i)) ){
0151: while(hnode!=NULL){
0152: Level++;
0153: printTree((struct Node *)(hnode->val.v.a));
0154: Level--;
0155: hnode=hnode->next;
0156: }
0157: }
0158: }
0159:
0160: if(node->element !=NULL){
0161: if(node->children->cnt!=0){
0162: mssWriteXmlIndent(Level,fpw);
0163: }
0164:
0165: xmlTag=mssInitXmlTag(node->element,NULL);
0166: mssWriteXmlEndTag(xmlTag,icid,fpw);
0167: mssFreeXmlTag(xmlTag);
0168: mssWriteRet(fpw);
0169: }
0170: }
0171:
0172: void freeTree(struct Node *node){
0173: struct mssHashNode *hnode;
0174: int i;
0175:
0176: if(node->children!=NULL){
0177: if(node->atts!=NULL){
0178: for(i=0; i<node->attCnt; i++){
0179: mssFree( *(node->atts+i*2+0) );
0180: mssFree( *(node->atts+i*2+1) );
0181: }
0182: mssFree(node->atts);
0183: }
0184: for(i=0; i<node->children->hashVal; i++){
0185: if( NULL != (hnode=*(node->children->node+i)) ){
0186: while(hnode!=NULL){
0187: freeTree((struct Node *)(hnode->val.v.a));
0188: hnode=hnode->next;
0189: }
0190: }
0191: }
0192: mssFreeHash(node->children);
0193: }
0194:
0195: if(node!=NULL) mssFree(node->element);
0196: mssFree(node);
0197: }
0198:
0199: /*----------------------------------------------------------------------------*/
0200: /* SAX ハンドラー */
0201: /*----------------------------------------------------------------------------*/
0202: void start_doc(XmlState *state){
0203:
0204: inEnc=mssStrdup((char *)ctxt->input->encoding);
0205: inVer=mssStrdup((char *)ctxt->version);
0206: mssWriteXmlDeclaration( inVer, inEnc, fpw );
0207: if(inEnc==NULL) inEnc=mssStrdup("UTF-8");
0208:
0209:
0210: /*出力のiconvオープン*/
0211: icid=iconv_open(inEnc,"UTF-8");
0212: if((int)icid==-1){
0213: mssShowErrMsg("encoding type error in iconv_open");
0214: mssEnd(mssErrorNoDefault);
0215: }
0216: }
0217:
0218: void end_doc(XmlState *state){
0219: printTree(tree);
0220: freeTree(tree);
0221:
0222: if(icid!=NULL) iconv_close(icid);
0223: }
0224:
0225: /*現在のNodeの子Nodeに指定されたelementがあれば、そのNodeを返す*/
0226: /*なければNULLを返す */
0227: struct Node *getChildNode(struct Node *cn, char *element){
0228: struct mssHashNode *node;
0229:
0230: if( cn->element==NULL) return(NULL);
0231: if( cn->children==NULL) return(NULL);
0232: node=(struct mssHashNode *) mssHashMember(cn->children, element);
0233:
0234: if( NULL == node){
0235: return(NULL);
0236: }else{
0237: return((struct Node *)node->val.v.a);
0238: }
0239: }
0240:
0241:
0242: struct Node *addNode(struct Node *cn, char *element){
0243: MssValue node;
0244:
0245: /*新しいノードの確保*/
0246: node.v.a=mssCalloc(sizeof(struct Node),"xmltree");
0247:
0248: /*エレメント名,新しいノードのアドレスをchildrenに登録*/
0249: mssHashInsert(cn->children, element, node);
0250:
0251: /*新しいノードの子ノードを初期化*/
0252: ((struct Node *)(node.v.a))->children = mssInitHash(11);
0253: ((struct Node *)(node.v.a))->element = mssStrdup(element);
0254: ((struct Node *)(node.v.a))->emptyTagFlg = 0;
0255: ((struct Node *)(node.v.a))->parent = cn;
0256: ((struct Node *)(node.v.a))->atts = NULL;
0257: ((struct Node *)(node.v.a))->attCnt = 0;
0258:
0259: return(node.v.a);
0260: }
0261:
0262: void addAtts(struct Node *node, char **atts){
0263: int i,j;
0264: int flg;
0265:
0266: if(atts!=NULL){
0267: i=0;
0268: while(*(atts+i)!=NULL){
0269:
0270: /*既に存在していればcontinue*/
0271: flg=0;
0272: for(j=0; j<node->attCnt; j++){
0273: if( 0==strcmp(*(atts+i),*(node->atts+j*2)) ){
0274: flg=1;
0275: break;
0276: }
0277: }
0278: if(flg){
0279: i=i+2;
0280: continue;
0281: }
0282:
0283: /*追加登録*/
0284: node->atts = mssRealloc(node->atts,
0285: sizeof(char *)*((node->attCnt+2)*2),"xmltree");
0286: *(node->atts+node->attCnt*2+0)=mssStrdup(*(atts+i));
0287: *(node->atts+node->attCnt*2+1)=mssStrdup("");
0288: *(node->atts+node->attCnt*2+2)=NULL;
0289: *(node->atts+node->attCnt*2+3)=NULL;
0290: i=i+2;
0291: node->attCnt++;
0292: }
0293: }
0294: }
0295:
0296: /*エレメント start */
0297: void start_element(XmlState *state, char *fullname, char **atts){
0298: struct Node *childNode;
0299:
0300: mssGV.inCnt++;
0301: if(state->level>MAX_NEST){
0302: mssShowErrMsg("nest level exceed (max=%d)" ,MAX_NEST);
0303: mssEnd(mssErrorNoDefault);
0304: }
0305:
0306: /*エレメントの子ノードを得る*/
0307: childNode=getChildNode(currentNode,fullname);
0308:
0309: /*エレメントの子ノードが無ければ追加する*/
0310: if( childNode==NULL ){
0311: childNode=addNode(currentNode,fullname);
0312: }
0313:
0314: /*属性を追加*/
0315: addAtts(childNode,atts);
0316:
0317: /*上の処理で得たエレメントの子ノードをカレントノードとする*/
0318: currentNode=childNode;
0319:
0320: state->level++;
0321: }
0322:
0323: /*エレメント end */
0324: void end_element(XmlState *state, char *fullname, char **atts){
0325: state->level--;
0326: if(state->level<0){
0327: mssShowErrMsg("nest level reach to below 0");
0328: mssEnd(mssErrorNoDefault);
0329: }
0330: currentNode=currentNode->parent;
0331: }
0332:
0333: /*sax error handler*/
0334: #include "saxerror.h"
0335:
0336: static xmlSAXHandler SAXFunctions = {
0337: NULL, /* internalSubset */
0338: NULL, /* isStandalone */
0339: NULL, /* hasInternalSubset */
0340: NULL, /* hasExternalSubset */
0341: NULL, /* resolveEntity */
0342: NULL, /* getEntity */
0343: NULL, /* entityDecl */
0344: NULL, /* notationDecl */
0345: NULL, /* attributeDecl */
0346: NULL, /* elementDecl */
0347: NULL, /* unparsedEntityDecl */
0348: NULL, /* setDocumentLocator */
0349: (startDocumentSAXFunc)start_doc, /* startDocument */
0350: (endDocumentSAXFunc)end_doc, /* endDocument */
0351: (startElementSAXFunc)start_element, /* startElement */
0352: (endElementSAXFunc)end_element, /* endElement */
0353: NULL, /* reference */
0354: NULL, /* characters */
0355: NULL, /* ignorableWhitespace */
0356: NULL, /* processingInstruction */
0357: NULL, /* comment */
0358: (warningSAXFunc) xmlSaxErrEnd, /* xmlParserWarning */
0359: (errorSAXFunc) xmlSaxErrEnd, /* xmlParserError */
0360: (fatalErrorSAXFunc) xmlSaxErrEnd, /* xmlParserError */
0361: NULL, /* getParameterEntity */
0362: };
0363:
0364: int main(int argc, char *argv[]){
0365:
0366: XmlState *state;
0367:
0368: /*----------------------------------------------------------------------------*/
0369: /* 前処理 */
0370: /*----------------------------------------------------------------------------*/
0371: mssInit(argc,argv,&comHelp); /* シグナル処理などの初期化 */
0372: mssHelpDoc(opt,&comHelp,argc,argv); /* ヘルプ */
0373: mssSetOption(opt,argc,argv); /* コマンドオプションの設定 */
0374:
0375: fpw=mssOpenFPW(optOTF.str,optZIP.set,0); /*標準出力オープン*/
0376:
0377: /*----------------------------------------------------------------------------*/
0378: /*メインルーチン */
0379: /*----------------------------------------------------------------------------*/
0380: tree=mssCalloc(sizeof(struct Node),"xmltree");
0381: tree->children = mssInitHash(11);
0382: currentNode=tree;
0383:
0384: state=mssCalloc(sizeof(XmlState),"xml2xt");
0385:
0386: if(optINF.set){
0387: ctxt=(xmlParserCtxtPtr)xmlCreateFileParserCtxt(optINF.str);
0388: }else{
0389: ctxt=(xmlParserCtxtPtr)xmlCreateFileParserCtxt("/dev/stdin");
0390: }
0391: if(!ctxt){
0392: mssShowErrMsg("not xml file\n");
0393: mssEnd(mssErrorNoDefault);
0394: }
0395: ctxt->sax=&SAXFunctions;
0396:
0397: ctxt->userData=state;
0398: xmlParseDocument(ctxt);
0399: ctxt->sax=NULL;
0400: xmlFreeParserCtxt(ctxt);
0401:
0402: mssFree(inEnc);
0403: mssFree(inVer);
0404: mssFree(state);
0405:
0406: /*----------------------------------------------------------------------------*/
0407: /*フッター出力&終了処理 */
0408: /*----------------------------------------------------------------------------*/
0409: mssCloseFPW(fpw); /*出力ファイルのクローズ */
0410: mssFreeOption(opt); /*オプション領域開放 */
0411: mssShowEndMsg(); /*完了メッセージ */
0412: mssEnd(mssExitSuccess); /*終了 */
0413: return(0); /* to avoid warning message*/
0414: }