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