MUSASHI C source: xml2xt.c


0001: /*============================================================================*/ 
0002: /* 変更履歴                                                                   */ 
0003: /*----------------------------------------------------------------------------*/ 
0004: /* 1.0 : 新しいAPIに対応(2003/06)                                             */ 
0005: /* 1.1 : -Sを10文字まで指定可能にする                                         */ 
0006: /*============================================================================*/ 
0007:    
0008: #include <musashi.h
0009: #include <stdio.h> 
0010: #include <stdlib.h> 
0011: #include <string.h> 
0012: #include <ctype.h> 
0013: #include <stdarg.h> 
0014: #include <libxml/parser.h> 
0015: #include <libxml/parserInternals.h> 
0016: #include <libxml/encoding.h> 
0017: #include <iconv.h> 
0018: #include <errno.h> 
0019: #include <regex.h> 
0020:  
0021: #include <xml2xtHelp.h> 
0022: struct mssComHelp comHelp={ 
0023:   "xml2xt",       /* コマンド名       */ 
0024:   "1.1",          /* バージョン       */ 
0025:   HELPT,          /* コマンドタイトル */                                     
0026:   HELPS,          /* 要約             */ 
0027:   HELPE,          /* 利用例           */ 
0028:   HELPR,          /* 参照コマンド     */ 
0029:   HELPA,          /* 作者情報         */ 
0030:   HELPB,          /* バグレポート情報 */ 
0031:   HELPH           /* ホームページ     */ 
0032: }; 
0033:  
0034: #define UNDEF 0 
0035: #define MAX_NEST 32 
0036: #define LOCAL_BUF 256 
0037: #define EncMax MssFieldMaxLen  /*iconvで使う出力用文字列長*/ 
0038:  
0039: /*----------------------------------------------------------------------------*/ 
0040: /* 構造体                                                                     */ 
0041: /*----------------------------------------------------------------------------*/ 
0042:  
0043: /* -f 項目名構造体                                      */ 
0044: /* ex) -f rec@id:recID                                  */ 
0045: /*        要素パス@属性名%オプション:新項目名           */ 
0046: /* data/rec@id%f:recID,/a/b@id%n:keyID                  */ 
0047: /*   eleNam[0][0]="data",[0][1]="rec",[0][2]=NULL       */ 
0048: /*   attNam[0]="id"                                     */ 
0049: /*   optNam[0][0]='f',[0][1]=0                          */ 
0050: /*   newNam[0]="recID"                                  */ 
0051: /*                                                      */ 
0052: /*   eleNam[1][0]="/",[1][1]="a",[1][2]="b",[1][3]=NULL */ 
0053: /*   attNam[1]="id"                                     */ 
0054: /*   optNam[1][0]='f',[1][1]=0                          */ 
0055: /*   newNam[1]="keyID"                                  */ 
0056:  
0057: struct XmlFld { 
0058:   int   cnt;                       /*項目数         */ 
0059:   char *element[MssFieldMaxCnt];   /*要素名UTF8     */ 
0060:   char *attribute[MssFieldMaxCnt]; /*属性名UTF8     */ 
0061:   char  option[MssFieldMaxCnt];    /*オプション t:テキスト,f:フラグ,n:名前 */ 
0062:   char *field[MssFieldMaxCnt];     /*新項目名UTF8   */ 
0063:  }; 
0064:  
0065:  
0066: struct XmlKey { 
0067:   char    **path;  /*-kで指定されたカンマで区切られた文字列*/ 
0068:   regex_t  *regex; /*上の文字列を正規表現にコンパイルしたもの*/ 
0069:   int       cnt;   /*キー要素の数*/ 
0070: }; 
0071:  
0072: typedef struct _XmlState { 
0073:   int level;            /* 現在処理中の要素Nodeのレベル(rootNode=0) */ 
0074: }XmlState; 
0075:  
0076: /*----------------------------------------------------------------------------*/ 
0077: /* グローバル変数                                                             */ 
0078: /*----------------------------------------------------------------------------*/ 
0079: extern xmlParserCtxtPtr ctxt; 
0080: extern struct mssGlobalVariables mssGV; 
0081:  
0082: static struct mssFPW    *fpw; /*出力ファイル構造体*/ 
0083: static struct mssHeader *hdo; /*出力ファイル用<head>タグ格納構造体*/ 
0084: static iconv_t *icid;   /*iconv用 変換ハンドラ*/ 
0085: static char *inEnc=NULL; /*エンコーディング*/ 
0086: static char *inVer=NULL; /*バージョン*/ 
0087: static char currentPath[4096]; /*現在処理中のパス (/a/b/c/)*/ 
0088: static char *inKeyStartPath=NULL; /*-kで指定したパスからの現在処理中の相対パス*/ 
0089: static int inKey;/*現在処理中の要素が-kで指定したいずれかのパスに入ってるか*/ 
0090: static int inFldNo[MssFieldMaxCnt];/*現在処理中の-fの番号*/ 
0091: static char   fldDat[MssFieldMaxCnt][MssFieldMaxLen];/*-fで指定された各項目の実際の値*/ 
0092: static struct XmlKey *key; 
0093: static struct XmlFld *fld; 
0094:  
0095:  
0096: /*============================================================================*/ 
0097: /* オプション宣言&定義                                                       */ 
0098: /*============================================================================*/ 
0099: /*----------------------------------------------------------------------------*/ 
0100: /* 一行の単位となるXMLタグのパス名                                            */ 
0101: /*----------------------------------------------------------------------------*/ 
0102:   MssOptSTR optKEY={ 
0103:     OSTR,   /* オプションタイプ                                             */ 
0104:     "k",    /* キーワード(複数文字は不可)                                   */ 
0105:     1,      /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視)      */ 
0106:     NULL,   /* デフォルト                                                   */ 
0107:     1,      /* 文字列の最小長                                               */ 
0108:     256,    /* 文字列の最大長                                               */ 
0109:     KEYT,   /* このオプションのタイトル(Helpで表示)                         */ 
0110:     KEYC    /* このオプションのコメント(Helpで表示)                         */ 
0111:   }; 
0112:  
0113: /*----------------------------------------------------------------------------*/ 
0114: /* 出力する項目のタグ名                                                       */ 
0115: /*----------------------------------------------------------------------------*/ 
0116:   MssOptSTR optFLD={ 
0117:     OSTR,   /* オプションタイプ                                             */ 
0118:     "f",    /* キーワード(複数文字は不可)                                   */ 
0119:     1,      /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視)      */ 
0120:     NULL  , /* デフォルト                                                   */ 
0121:     1,      /* 文字列の最小長                                               */ 
0122:     1024,   /* 文字列の最大長                                               */ 
0123:     FLDT,   /* このオプションのタイトル(Helpで表示)                         */ 
0124:     FLDC    /* このオプションのコメント(Helpで表示)                         */ 
0125:   }; 
0126:  
0127: /*----------------------------------------------------------------------------*/ 
0128: /* spaceを何に変換するか                                                      */ 
0129: /*----------------------------------------------------------------------------*/ 
0130:   MssOptSTR optSPC={ 
0131:     OSTR,   /* オプションタイプ                                             */ 
0132:     "S",    /* キーワード(複数文字は不可)                                   */ 
0133:     0,      /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視)      */ 
0134:     "_",    /* デフォルト                                                   */ 
0135:     0,      /* 文字列の最小長                                               */ 
0136:     10,     /* 文字列の最大長                                               */ 
0137:     SPCT,   /* このオプションのタイトル(Helpで表示)                         */ 
0138:     SPCC    /* このオプションのコメント(Helpで表示)                         */ 
0139:   }; 
0140:  
0141: /*----------------------------------------------------------------------------*/ 
0142: /* 入力ファイル                                                               */ 
0143: /*----------------------------------------------------------------------------*/ 
0144:   MssOptINF optINF={ 
0145:     OINF,   /* オプションタイプ                                             */ 
0146:     "i",    /* キーワード(複数文字は不可)                                   */ 
0147:     0,      /* 0:オプション, 1:必須                                         */ 
0148:     1,      /* 指定可能の最大ファイル数                                     */ 
0149:     0,      /*1:file not foundのエラーで終了しない 0:する                   */ 
0150:     INFT,   /* このオプションのタイトル(Helpで表示)                         */ 
0151:     INFC    /* このオプションのコメント(Helpで表示)                         */ 
0152:   }; 
0153:  
0154: /*----------------------------------------------------------------------------*/ 
0155: /* 出力ファイル                                                               */ 
0156: /*----------------------------------------------------------------------------*/ 
0157:   MssOptOTF optOTF={ 
0158:     OOTF,   /* オプションタイプ                                             */ 
0159:     "o",    /* キーワード(複数文字は不可)                                   */ 
0160:     0,      /* 0:オプション, 1:必須                                         */ 
0161:     OTFT,   /* このオプションのタイトル(Helpで表示)                         */ 
0162:     OTFC    /* このオプションのコメント(Helpで表示)                         */ 
0163:   }; 
0164:  
0165: /*----------------------------------------------------------------------------*/ 
0166: /* 圧縮出力                                                                   */ 
0167: /*----------------------------------------------------------------------------*/ 
0168:   MssOptFLG optZIP={ 
0169:     OFLG,   /* オプションタイプ                                             */ 
0170:     "z",    /* キーワード(複数文字は不可)                                   */ 
0171:     0,      /* デフォルト(基本的には0) 常にonにしたいときは1にする          */ 
0172:     ZIPT,   /* このオプションのタイトル(Helpで表示)                         */ 
0173:     ZIPC    /* このオプションのコメント(Helpで表示)                         */ 
0174:   }; 
0175:  
0176: /*----------------------------------------------------------------------------*/ 
0177: /* オプションをまとめる                                                       */ 
0178: /*----------------------------------------------------------------------------*/ 
0179: void *opt[]={&optKEY,&optFLD,&optSPC,&optINF,&optOTF,&optZIP,NULL}; 
0180:      
0181: /*----------------------------------------------------------------------------*/ 
0182: /* -k のトークン分割+encoding                                                 */ 
0183: /*----------------------------------------------------------------------------*/ 
0184: static void setXmlKey(void){ 
0185:   int i; 
0186:   char *pos; 
0187:   char *keyPos[MssFieldMaxCnt]; 
0188:  
0189:   key=mssCalloc(sizeof(struct XmlKey),"setXmlKey"); 
0190:   if(optKEY.set){ 
0191:  
0192:     /* カンマによるトークン分割 */ 
0193:     i=0; 
0194:     pos = strtok(optKEY.str,","); 
0195:     while(pos!=NULL){ 
0196:       keyPos[i++]=pos; 
0197:       pos=strtok(NULL,","); 
0198:     } 
0199:     key->cnt=i; 
0200:  
0201:     /* encoding してpathにセット */ 
0202:     key->path=mssCalloc(sizeof(char *),"xml2xt"); 
0203:     for(i=0; i<key->cnt; i++){ 
0204:       *(key->path+i)=mssEncoding(keyPos[i],icid); 
0205:     } 
0206:   }else{ 
0207:     key->path=NULL; 
0208:   } 
0209:  
0210:   key->regex=mssCalloc(sizeof(regex_t)*key->cnt,"xml2xt"); 
0211:   for(i=0; i<key->cnt; i++){ 
0212:     if( regcomp(key->regex+i,*(key->path+i),REG_EXTENDED) ){ 
0213:       mssShowErrMsg("error in compiling regex"); 
0214:       mssEnd(mssErrorNoDefault); 
0215:     } 
0216:   } 
0217: } 
0218:  
0219: static void freeXmlKey(struct XmlKey *key){ 
0220:   int i; 
0221:   if(key!=NULL){ 
0222:     for(i=0; i<key->cnt; i++){ 
0223:       if(*(key->path+i)!=NULL) mssFree(*(key->path+i)); 
0224:       regfree(key->regex+i); 
0225:     } 
0226:     mssFree(key->regex); 
0227:     mssFree(key->path); 
0228:     mssFree(key); 
0229:   } 
0230: } 
0231:  
0232: /*----------------------------------------------------------------------------*/ 
0233: /* -f のトークン分割+encoding                                                 */ 
0234: /* data/rec@id%f:recID,/a/b@id%n:keyID                                        */ 
0235: /*----------------------------------------------------------------------------*/ 
0236: static struct XmlFld *setXmlFld(){ 
0237:   int i,j; 
0238:   char *pos; 
0239:   struct XmlFld *fld=NULL; 
0240:   char *element[MssFieldMaxCnt];    /*encode前の要素名     */ 
0241:   char *attribute[MssFieldMaxCnt];  /*encode前の属性名     */ 
0242:   char  option[MssFieldMaxCnt];     /*encode前のオプション */ 
0243:   char *field[MssFieldMaxCnt];      /*encode前の新項目名   */ 
0244:   char tmp[4096]; 
0245:  
0246:   fld=mssCalloc(sizeof(struct XmlFld),"setXmlFld"); 
0247:  
0248:   /*カンマのトークン分割(要素名の先頭アドレスをセット)*/ 
0249:   /* data/rec@id%f:recID|/a/b@id%n:keyID              */ 
0250:   fld->cnt=0; 
0251:   pos = strtok(optFLD.str,","); 
0252:   while(pos!=NULL){ 
0253:     if(fld->cnt>=MssFieldMaxCnt){ 
0254:       mssShowErrMsg("too many fields on -f"); 
0255:       mssEnd(mssErrorNoDefault); 
0256:  
0257:     } 
0258:     element[fld->cnt]=pos; 
0259:     fld->cnt++; 
0260:     pos=strtok(NULL,","); 
0261:   } 
0262:  
0263:   /*コロンでトークン分割(新項目名のセット:strdup)*/ 
0264:   /* data/rec@id%f|recID|/a/b@id%n|keyID  */ 
0265:   for(i=0; i<fld->cnt; i++){ 
0266:     pos=strchr(element[i],':'); 
0267:     if(pos!=NULL){ 
0268:       *pos='\0'; 
0269:       field[i]=mssStrdup(++pos); 
0270:     }else{ 
0271:       field[i]=NULL; 
0272:     } 
0273:   } 
0274:  
0275:   /*%でトークン分割(オプションのセット)  */ 
0276:   /* data/rec@id|f|recID|/a/b@id|n|keyID  */ 
0277:   for(i=0; i<fld->cnt; i++){ 
0278:     j=0; 
0279:     pos = strchr(element[i],'%'); 
0280:     if(pos!=NULL){ 
0281:       *pos='\0'; 
0282:       option[i]=*(++pos); 
0283:     }else{ 
0284:       option[i]=0; 
0285:     } 
0286:   } 
0287:  
0288:   /*この段階で新項目名が指定されていなければ、 
0289:     要素名+属性名を新項目名として登録する*/ 
0290:   for(i=0; i<fld->cnt; i++){ 
0291:     if(field[i]==NULL){ 
0292:       field[i]=mssStrdup(element[i]); 
0293:     } 
0294:   } 
0295:  
0296:   /*@でトークン分割(属性名のセット)*/ 
0297:   /* data/rec|id|f|recID|/a/b|id|n|keyID  */ 
0298:   for(i=0; i<fld->cnt; i++){ 
0299:     pos=strchr(element[i],'@'); 
0300:     if(pos!=NULL){ 
0301:       *pos='\0'; 
0302:       attribute[i]=++pos; 
0303:     }else{ 
0304:       attribute[i]=NULL; 
0305:     } 
0306:   } 
0307:  
0308:   /*-----------------------------------*/ 
0309:   /*UTF8へのencoding + 構造体へのセット*/ 
0310:   /*-----------------------------------*/ 
0311:   for(i=0; i<fld->cnt; i++){ 
0312:  
0313:     /*要素*/ 
0314:     /* 要素の最後に"/"を加える */ 
0315:     if(*(element[i]+strlen(element[i])-1)!='/'){ 
0316:       strcpy(tmp,element[i]); 
0317:       strcat(tmp,"/"); 
0318:     }else{ 
0319:       strcpy(tmp,element[i]); 
0320:     } 
0321:     fld->element[i]=mssEncoding(tmp,icid); 
0322:  
0323:     /*属性*/ 
0324:     fld->attribute[i]=mssEncoding(attribute[i],icid); 
0325:  
0326:     /*パラメータ*/ 
0327:     fld->option[i]=option[i]; 
0328:  
0329:     /*新項目名*/ 
0330:     fld->field[i]=mssEncoding(field[i],icid); 
0331:   } 
0332:  
0333:   for(i=0; i<fld->cnt; i++){ 
0334:     mssFree(field[i]); 
0335:   } 
0336:  
0337:   return(fld); 
0338: } 
0339:  
0340: static void freeXmlFld(struct XmlFld *fld){ 
0341:   int i; 
0342:  
0343:   for(i=0; i<fld->cnt; i++){ 
0344:     if(fld->element[i]  !=NULL) mssFree(fld->element[i]); 
0345:     if(fld->attribute[i]!=NULL) mssFree(fld->attribute[i]); 
0346:     if(fld->field[i]    !=NULL) mssFree(fld->field[i]); 
0347:   } 
0348:   if(fld!=NULL)mssFree(fld); 
0349: } 
0350:  
0351: static void writeEncStr(char *str){ 
0352:   char *buf; 
0353:  
0354:   if( str!=NULL && *str!='\0') { 
0355:     buf=mssEncoding(str,icid); 
0356:     mssWriteStr(buf,fpw); 
0357:     if(buf!=NULL && buf!=str) mssFree(buf); 
0358:   }else{ 
0359:     mssWriteStr("*",fpw); 
0360:   } 
0361: } 
0362:  
0363: /*左右のスペースを省き、途中のスペースを指定の文字列に変換する*/ 
0364: static char *chgSpc(char *str){ 
0365:   int repStrLen; 
0366:   int cnt; 
0367:   char *pos; 
0368:   char *last; 
0369:   char *newStr; /*スペースを変換して保存する文字列領域*/ 
0370:   char *retStr; /*返値用の文字列*/ 
0371:  
0372:   if(str==NULL) return(NULL); 
0373:  
0374:   newStr=mssMalloc(sizeof(char)*(MssFieldMaxLen+1),"chgSpc"); 
0375:   *newStr='\0'; 
0376:  
0377:   repStrLen=strlen(optSPC.str); 
0378:  
0379:   /*左のスペース文字をスキップ*/ 
0380:   while(*str!='\0'){ 
0381:     if(!isspace(*str)) break; 
0382:     str++; 
0383:   } 
0384:  
0385:   /*右のスペース文字を省く*/ 
0386:   last=str+strlen(str)-1; 
0387:   if(str==last+1) return(newStr); 
0388:   while(*last==' '){ 
0389:     if(!isspace(*last)) break; 
0390:     *last--='\0'; 
0391:   } 
0392:  
0393:   cnt=0; 
0394:   pos=newStr; 
0395:   while(*str!='\0'){ 
0396:     if(*str==' '){ 
0397:       /*項目最大長を超えたらそこで打ち切り*/ 
0398:       if(cnt+repStrLen>=MssFieldMaxLen-1){ 
0399:         break; 
0400:       } 
0401:       strncpy(pos,optSPC.str,repStrLen); 
0402:       pos+=repStrLen; 
0403:       str++; 
0404:       cnt+=repStrLen; 
0405:     }else{ 
0406:       *pos++=*str++; 
0407:       cnt++; 
0408:     } 
0409:   } 
0410:   *pos='\0'; 
0411:  
0412:   retStr=mssStrdup(newStr); 
0413:   mssFree(newStr); 
0414:   return(retStr); 
0415: } 
0416:   
0417: /*fldDatを出力*/ 
0418: static void printDat(XmlState *state){ 
0419:   int fn; 
0420:   char *str; 
0421:  
0422:   for(fn=0; fn<fld->cnt-1; fn++){ 
0423:     str=chgSpc(fldDat[fn]); 
0424:     writeEncStr(str); 
0425:     mssFree(str); 
0426:     mssWriteDlm(fpw); 
0427:   } 
0428:     str=chgSpc(fldDat[fn]); 
0429:     writeEncStr(str); 
0430:     mssFree(str); 
0431:     mssWriteRet(fpw); 
0432:   mssGV.outCnt++; 
0433: } 
0434:  
0435: /*fldDatをクリア*/ 
0436: static void clearFldDat(XmlState *state){ 
0437:   int i; 
0438:  
0439:   for(i=0; i<fld->cnt; i++){ 
0440:     /*絶対パス指定(キー要素)の項目はクリアしない*/ 
0441:     if(*fld->element[i]!='/') fldDat[i][0]='\0'; 
0442:   } 
0443: } 
0444:  
0445: void Strncpy(char *to, char *from, int len){ 
0446:   int i,j; 
0447:  
0448:   i=0; 
0449:   for(j=0; j<len; j++){ 
0450:     *(to+i)=*(from+j); 
0451:     if((++i)>=MssFieldMaxLen-1) { 
0452:       mssShowErrMsg("exceed maximum length of field"); 
0453:       mssEnd(mssErrorNoDefault); 
0454:     } 
0455:   } 
0456:   *(to+i)='\0'; 
0457: } 
0458:  
0459: void Strncat(char *to, char *from, int len){ 
0460:   int i,j; 
0461:  
0462:   i=strlen(to); 
0463:   for(j=0; j<len; j++){ 
0464:     *(to+i)=*(from+j); 
0465:     if((++i)>=MssFieldMaxLen-1) { 
0466:       mssShowErrMsg("exceed maximum length of field"); 
0467:       mssEnd(mssErrorNoDefault); 
0468:     } 
0469:   } 
0470:   *(to+i)='\0'; 
0471: } 
0472:  
0473: /*----------------------------------------------------------------------------*/ 
0474: /* SAX ハンドラー                                                             */ 
0475: /*----------------------------------------------------------------------------*/ 
0476: /*############## start_doc */ 
0477: void start_doc(XmlState *state){ 
0478:   int i; 
0479:  
0480:   inEnc=mssStrdup((char *)ctxt->input->encoding); 
0481:   inVer=mssStrdup((char *)ctxt->version); 
0482:   if(inEnc==NULL) inEnc=mssStrdup("UTF-8"); 
0483:  
0484:   /*パラメータ用のiconvオープン                                   */ 
0485:   /*xmlコマンドのパラメータ、入力データ、出力データのencoding     */ 
0486:   /*は全て、入力データのエンコーディングとおなじことを前提に作る。*/ 
0487:   icid=iconv_open("UTF-8",inEnc); 
0488:   if((int)icid==-1) { 
0489:     mssShowErrMsg("encoding type error in iconv_open"); 
0490:     mssEnd(mssErrorNoDefault); 
0491:   } 
0492:  
0493:   /* -k,-f パラメータのセット+漢字をUTF-8に変換 */ 
0494:   setXmlKey(); 
0495:   fld=setXmlFld(key); 
0496:  
0497:   /*パラメータ用のiconvクローズ*/ 
0498:   if(icid!=NULL) iconv_close(icid); 
0499:  
0500:   /*出力のiconvオープン*/ 
0501:   icid=iconv_open(inEnc,"UTF-8"); 
0502:   if((int)icid==-1) { 
0503:     mssShowErrMsg("encoding type error in iconv_open"); 
0504:     mssEnd(mssErrorNoDefault); 
0505:   } 
0506:  
0507:   /*出力ヘッダーの作成と出力   */ 
0508:   hdo=mssInitHeader(NULL,NULL); 
0509:   for(i=0; i<fld->cnt; i++){ 
0510:     mssAddFieldsByStr( hdo->flds, mssEncoding(fld->field[i],icid) ); 
0511:   } 
0512:  
0513:   /*xmlTableヘッダーの書き出し*/ 
0514:   mssWriteHeader(hdo, fpw); 
0515:  
0516:   /* currentPathの初期化 */ 
0517:   currentPath[0]='/'; 
0518:   currentPath[1]='\0'; 
0519:  
0520:   for(i=0; i<fld->cnt; i++){ 
0521:     inFldNo[i]=0; 
0522:   } 
0523: } 
0524:  
0525: /*############## end_doc */ 
0526: void end_doc(XmlState *state){ 
0527:   /*出力用のiconvクローズ*/ 
0528:   if(icid!=NULL) iconv_close(icid); 
0529: } 
0530:  
0531: /*-kのキーに入ったならば1を返す。その他は0。*/ 
0532: static int isInKey(void){ 
0533:   int i; 
0534:   for(i=0; i<key->cnt; i++){ 
0535:     /*0でマッチ*/ 
0536:     if(0==regexec(key->regex+i,currentPath,0,NULL,0)) return(1); 
0537:   } 
0538:   return(0); 
0539: } 
0540:  
0541: /*----------------------------------------------*/ 
0542: /*-fの要素に入ったならば、その要素の番号を返す。*/ 
0543: /* inFldNo[]に当てはまる項目番号をセットし、    */ 
0544: /* inFldCntにその項目数をセットする。           */ 
0545: /*----------------------------------------------*/ 
0546: static void setInFld(){ 
0547:   int i; 
0548:  
0549:   for(i=0; i<fld->cnt; i++){ 
0550:     if(*fld->element[i]=='/'){ /* ----- 絶対パスの場合 ( -f /a/b ) */ 
0551:       if(currentPath!=NULL){ 
0552:         if(0==strcmp(currentPath,fld->element[i])){ 
0553:           inFldNo[i]=1; 
0554:         } 
0555:       } 
0556:     }else{                     /* ----- 相対パスの場合 ( -f a/b ) */ 
0557:       if(inKeyStartPath!=NULL){ 
0558:         if(0==strcmp(inKeyStartPath,fld->element[i])){ 
0559:           inFldNo[i]=1; 
0560:         } 
0561:       } 
0562:     } 
0563:   } 
0564: } 
0565:  
0566: static void unsetInFld(){ 
0567:   int i; 
0568:  
0569:   for(i=0; i<fld->cnt; i++){ 
0570:     if(*fld->element[i]=='/'){ /* ----- 絶対パスの場合 ( -f /a/b ) */ 
0571:       if(currentPath!=NULL){ 
0572:         if(0==strcmp(currentPath,fld->element[i])){ 
0573:           inFldNo[i]=0; 
0574:         } 
0575:       } 
0576:     }else{                     /* ----- 相対パスの場合 ( -f a/b ) */ 
0577:       if(inKeyStartPath!=NULL){ 
0578:         if(0==strcmp(inKeyStartPath,fld->element[i])){ 
0579:           inFldNo[i]=0; 
0580:         } 
0581:       } 
0582:     } 
0583:   } 
0584: } 
0585:  
0586: static char *getAttVal(char *attName, char **atts) { 
0587:   int i; 
0588:  
0589:   if(atts==NULL || attName==NULL) return(NULL); 
0590:  
0591:   i=0; 
0592:   while(1){ 
0593:     if( *(atts+i)==NULL ) return(NULL); 
0594:     if( 0==strcmp(attName,*(atts+i)) ){ 
0595:       return(*(atts+i+1)); 
0596:     } 
0597:     i=i+2; 
0598:   } 
0599: } 
0600:  
0601: /*############## start_element */ 
0602: void start_element(XmlState *state, char *fullname, char **atts){ 
0603:   char *attVal; 
0604:   int prvInKey=inKey; 
0605:  
0606:   int i; 
0607:  
0608:   mssGV.inCnt++; 
0609:  
0610:   /*現在のノードパスを更新*/ 
0611:   strcat(currentPath,fullname); 
0612:   strcat(currentPath,"/"); 
0613:  
0614:   /*-kのキーに入ったかどうか*/ 
0615:   inKey=isInKey(); 
0616:  
0617:   /*初めてキーに入った場合 キー内の開始文字位置をセット*/ 
0618:   if(prvInKey==0 && inKey==1){ 
0619:     inKeyStartPath=currentPath+strlen(currentPath); 
0620:   } 
0621:  
0622:   /*-fで指定したどの要素に入っているか*/ 
0623:   setInFld(); 
0624:  
0625:   for(i=0; i<fld->cnt; i++){ 
0626:     if(inFldNo[i]){ 
0627:       /*属性指定項目の場合(<a id="aaa">)*/ 
0628:       if(fld->attribute[i]!=NULL){ 
0629:         attVal=getAttVal(fld->attribute[i],atts); 
0630:         if( attVal!=NULL ){ 
0631:           switch(fld->option[i]){ 
0632:           case 'f': /*フラグ*/ 
0633:             fldDat[i][0]='1'; 
0634:             fldDat[i][1]='\0'; 
0635:             break; 
0636:           case 'n': /*名前(要素名+属性名)*/ 
0637:             Strncpy(fldDat[i],currentPath,strlen(currentPath)); 
0638:             fldDat[i][strlen(currentPath)-1]='\0'; /*最後の"/"を消す*/ 
0639:             Strncat(fldDat[i],"@",1); 
0640:             Strncat(fldDat[i],fld->attribute[i],strlen(fld->attribute[i])); 
0641:             break; 
0642:           default: /*テキスト(デフォルト)*/ 
0643:             Strncpy(fldDat[i],attVal,strlen(attVal)); 
0644:             break; 
0645:           } 
0646:         } 
0647:  
0648:       /*要素指定項目の場合(<a>)*/ 
0649:       }else{ 
0650:         switch(fld->option[i]){ 
0651:         case 'f': /*フラグ*/ 
0652:           fldDat[i][0]='1'; 
0653:           fldDat[i][1]='\0'; 
0654:           break; 
0655:         case 'n': /*名前(要素名+属性名)*/ 
0656:           Strncpy(fldDat[i],currentPath,strlen(currentPath)); 
0657:           fldDat[i][strlen(currentPath)-1]='\0'; /*最後の"/"を消す*/ 
0658:           break; 
0659:         default: /*テキスト(デフォルト)*/ 
0660:           /*要素内テキスト指定の場合(<a>text</a>)はcharacerにてセットする*/ 
0661:           /*同じ要素が出て来たときのために、前のデータをクリアする*/ 
0662:           fldDat[i][0]='\0'; /*最後の"/"を消す*/ 
0663:           break; 
0664:         } 
0665:       } 
0666:     } 
0667:   } 
0668:   state->level++; 
0669: } 
0670:  
0671: /*############## end_element */ 
0672: void end_element(XmlState *state, char *fullname, char **atts){ 
0673:   int prvInKey=inKey; 
0674:   char *pos; 
0675:  
0676:   unsetInFld(); 
0677:  
0678:   state->level--; 
0679:  
0680:   /*現在のノードパスを更新*/ 
0681:   pos=currentPath+strlen(currentPath)-2; 
0682:   while(*pos!='/') pos--; 
0683:   *(++pos)='\0'; 
0684:  
0685:   /*今回のend_elementでキーを出たならば*/ 
0686:   inKey=isInKey(); 
0687:   if(prvInKey==1 && inKey==0){ 
0688:     /*キーから出る場合 キー内の開始文字位置をNULLにセット*/ 
0689:     inKeyStartPath=NULL; 
0690:     /*データ出力*/ 
0691:     printDat(state); 
0692:     clearFldDat(state); 
0693:   } 
0694:  
0695:   /*-fで指定したどの要素に入っているか*/ 
0696:   /*end_elementでは、テキスト指定項目の時のみ、調査する*/ 
0697:  
0698: } 
0699:  
0700: /*############## start_characters */ 
0701: void start_characters(XmlState *state, xmlChar *chars, int len){ 
0702:   int i; 
0703:  
0704:   for(i=0; i<fld->cnt; i++){ 
0705:     if(inFldNo[i]){ 
0706:       /*属性でなく、要素の場合*/ 
0707:       if(fld->attribute[i]==NULL){ 
0708:         /*%n,%fでない場合*/ 
0709:         if(fld->option[i]==0){ 
0710:           /* fldDat[i][0]='\0'; start_elementでクリアに変更*/ 
0711:           Strncat(fldDat[i],chars,len); 
0712:         } 
0713:       } 
0714:     } 
0715:   } 
0716: } 
0717:  
0718: /*sax error handler*/ 
0719: #include "saxerror.h" 
0720:  
0721: void xmlSaxErrEndLocal(void *ctx, const char *msg, ...){ 
0722:    
0723:   XmlState *dummy=NULL; 
0724:  
0725:   if(0==strncmp(msg,"Document is empty",17)){ 
0726:      
0727:     ctxt->input->encoding=MssXmlDefEnc
0728:     start_doc(dummy); 
0729:     mssWriteFooter(fpw); 
0730:     mssCloseFPW(fpw); 
0731:     mssShowEndMsg(); 
0732:     mssEnd(mssExitSuccess); 
0733:   }else{ 
0734:      xmlSaxErrEnd(ctx, msg); 
0735:   } 
0736: } 
0737:  
0738:  
0739: static xmlSAXHandler SAXFunctions = { 
0740:     NULL, /* internalSubset */ 
0741:     NULL, /* isStandalone */ 
0742:     NULL, /* hasInternalSubset */ 
0743:     NULL, /* hasExternalSubset */ 
0744:     NULL, /* resolveEntity */ 
0745:     NULL, /* getEntity */ 
0746:     NULL, /* entityDecl */ 
0747:     NULL, /* notationDecl */ 
0748:     NULL, /* attributeDecl */ 
0749:     NULL, /* elementDecl */ 
0750:     NULL, /* unparsedEntityDecl */ 
0751:     NULL, /* setDocumentLocator */ 
0752:     (startDocumentSAXFunc)start_doc, /* startDocument */ 
0753:     (endDocumentSAXFunc)end_doc, /* endDocument */ 
0754:     (startElementSAXFunc)start_element, /* startElement */ 
0755:     (endElementSAXFunc)end_element, /* endElement */ 
0756:     NULL, /* reference */ 
0757:     (charactersSAXFunc) start_characters, /* characters */ 
0758:     NULL, /* ignorableWhitespace */ 
0759:     NULL, /* processingInstruction */ 
0760:     NULL, /* comment */ 
0761:     (warningSAXFunc) xmlSaxErrEndLocal, /* xmlParserWarning */ 
0762:     (errorSAXFunc) xmlSaxErrEndLocal, /* xmlParserError */ 
0763:     (fatalErrorSAXFunc) xmlSaxErrEndLocal, /* xmlParserError */ 
0764:     NULL, /* getParameterEntity */ 
0765:     NULL, 
0766: }; 
0767:  
0768:  
0769: int main(int argc, char *argv[]){ 
0770:  
0771:   XmlState      *state; 
0772:  
0773:   char *tmp; 
0774:   char *fname; 
0775:  
0776: /*----------------------------------------------------------------------------*/ 
0777: /* 前処理                                                                     */ 
0778: /*----------------------------------------------------------------------------*/ 
0779:   mssInit(argc,argv,&comHelp); /* シグナル処理などの初期化     */ 
0780:   mssHelpDoc(opt,&comHelp,argc,argv);/* ヘルプ                       */ 
0781:   mssSetOption(opt,argc,argv);    /* コマンドオプションの設定     */ 
0782:  
0783: /*prnOption(opt);*/ 
0784:  
0785:   tmp=optSPC.str; 
0786:   while(*tmp!='\0'){ 
0787:     if(isspace(*tmp++)) { 
0788:       mssShowErrMsg("cannot use space character in -S option"); 
0789:       mssEnd(mssErrorNoDefault); 
0790:     } 
0791:   } 
0792:  
0793:   fpw=mssOpenFPW(optOTF.str,optZIP.set,0); /*標準出力オープン*/ 
0794:  
0795: /*----------------------------------------------------------------------------*/ 
0796: /*メインルーチン                                                              */ 
0797: /*----------------------------------------------------------------------------*/ 
0798:   state=mssCalloc(sizeof(XmlState),"xml2xt"); 
0799:   state->level = 0; 
0800:  
0801:   if(optINF.set){ 
0802:     fname=optINF.str; 
0803:   }else{ 
0804:     fname="/dev/stdin"; 
0805:   } 
0806:  
0807:   ctxt=(xmlParserCtxtPtr)xmlCreateFileParserCtxt(fname); 
0808:   if(!ctxt){ 
0809:     fprintf(stderr,"not xml\n"); 
0810:   } 
0811:   ctxt->sax=&SAXFunctions; 
0812:   ctxt->userData=state; 
0813:   xmlParseDocument(ctxt); 
0814:   ctxt->sax=NULL; 
0815:   xmlFreeParserCtxt(ctxt); 
0816:  
0817:   freeXmlKey(key); 
0818:   freeXmlFld(fld); 
0819:   mssFree(state); 
0820:  
0821: /*----------------------------------------------------------------------------*/ 
0822: /*フッター出力&終了処理                                                       */ 
0823: /*----------------------------------------------------------------------------*/ 
0824:   mssWriteFooter(fpw);    /*フッターの出力*/ 
0825:   mssCloseFPW(fpw);       /*出力ファイルのクローズ*/ 
0826:   mssFreeHeader(hdo);     /*出力ヘッダ領域開放*/ 
0827:   mssFreeOption(opt);     /*オプション領域開放*/ 
0828:   mssShowEndMsg();        /*完了メッセージ*/ 
0829:   mssEnd(mssExitSuccess); /*終了*/ 
0830:   return(0); /* to avoid warning message*/ 
0831: }