Skip to content

Instantly share code, notes, and snippets.

@brokendish
Created August 25, 2013 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brokendish/6333931 to your computer and use it in GitHub Desktop.
Save brokendish/6333931 to your computer and use it in GitHub Desktop.
xml_CSV_Getlib.c
#include <stdio.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <regex.h>
#include "xml_CSV_Getlib.h"
/* デバグ用定義 */
/*#define DEBUG1*/
/*
--------------------------------------------------------------------
気象庁のMXLファイルから必要な部分を抽出してCSVファイルにする
対応するXMLデータの入力方式
 ・XMLデータのメモリからの入力(電文) パラメータ(opt=0)を指定時
 ・XMLファイルの場所を指定しての入力 パラメータ(opt=1)を指定時
 ・標準入力からのXML入力      パラメータ(opt=2)を指定時
作成中
・まだ、作成中
--------------------------------------------------------
名前
xmlCSV_Get_Main
XMLデータ(電文、ファイル)からXPATHで指定した内容をリスト表示する
書式
xmlCSV_Get_Main(int opt, char *input_file, char *xpat[], char *nmsp[])
[int opt]   0:メモリーから読込 1:ファイルから読込 2:標準入力から読込(パイプで入力)
[char *input_file] (opt=0):XML文字列(電文) (opt=1):XMLファイルのフルパス (opt=2):標準入力から取得
[char *xpat[]] XML XPATHの配列※1
[char *nmsp[]]   MXL名前空間(ネームスペース)の配列※2
    ※1)Ex
    char *xpat[5];
xstr_xpt[0]= "/x:Report/x:Control/x:Status";
xstr_xpt[1]= "/x:Report/xh:Head/xh:TargetDateTime";
xstr_xpt[2]= "/x:Report/xb:Body/xb:MeteorologicalInfos/xb:MeteorologicalInfo/xb:Item/xb:Station/xb:Name";
xstr_xpt[3]= "/x:Report/xb:Body/xb:MeteorologicalInfos/xb:MeteorologicalInfo/xb:Item/xb:Station/xb:Location";
xstr_xpt[4]= "/x:Report/xb:Body/xb:AdditionalInfo/xb:ObservationAddition/xb:Text";
    ※2)Ex
    char *nmsp[3];
xstr_nsp[0]= "x,http://xml.kishou.go.jp/jmaxml1/";
xstr_nsp[1]= "xh,http://xml.kishou.go.jp/jmaxml1/informationBasis1/";
xstr_nsp[2]= "xb,http://xml.kishou.go.jp/jmaxml1/body/meteorology1/";
説明
【実行 (opt=0)】
xmlCSV_Get_Main(0,<>.....</>(XML文字列),**xpat(配列データ),**nmsp(配列データ));
【実行 (opt=1)】
xmlCSV_Get_Main(1,/etc/zz/xxx.xml(XMLファイル格納場所),**xpat(配列データ),**nmsp(配列データ));
【実行 (opt=2)】
xmlCSV_Get_Main(0,<>.....</>(標準入力からのXML文字列),**xpat(配列データ),**nmsp(配列データ));
(例:ドライバからの実行 cat tokusyu-3.xml|./xml_CSV 2)
【コンパイル方法】
gcc -o xml_CSV xml_CSV_Get.c xml_CSV_Getlib.c -lxml2
【デバグ用コンパイル(DEBUG1)】
gcc -D DEBUG1 -o xml_CSV xml_CSV_Get.c xml_CSV_Getlib.c -lxml2
【ファイル読込用の実行 (opt=1)】
./xml_CSV 1 ./tokusyu-3.xml
【メモリー読込用の実行 (opt=0)】
./xml_CSV 0 "`cat tokusyu-3.xml`"
【標準入力読込用の実行 (opt=2)】
cat tokusyu-3.xml|./xml_CSV 2
    【コンパイル&実行】
    gcc -o xml_CSV xml_CSV_Get.c xml_CSV_Getlib.c -lxml2 && cat tokusyu-3.xml|./xml_CSV 2
--------------------------------------------------------------------
*/
/*
----------------------------------------------------------------------
xmlns属性(XML名前空間(ネームスペース))用 構造体
----------------------------------------------------------------------
"xml_CSV_Get.h"
----------------------------------------------------------------------
XML Xpath取得用 構造体
----------------------------------------------------------------------
"xml_CSV_Get.h"
----------------------------------------------------------------------
関数定義
----------------------------------------------------------------------
"xml_CSV_Get.h"
*/
/*
--------------------------------------------------------------------------------------------------------
メイン処理(配列で受け取ったデータをリスト構造体に格納する)
 XMLパースに必要な情報「XMLデータの入力方式(opt)」、「XMLデータ」、「XML名前空間」、「Xpath」
 を引数として受け取りXpathで指定された部分をXMLデータから抽出する
 【引数】
int opt :XMLの入力を判別する(0:メモリーから読込 1:ファイルから読込 2:標準入力から読込(パイプで入力))
char *input_file :XMLデータ文字列又は、XMLファイルへのパス
char *xpat[] :取得するXpathの配列データ
char *nmsp[] :XML名前空間配列データ
--------------------------------------------------------------------------------------------------------
*/
int xmlCSV_Get_Main(int opt, char *input_file, char *xpat[], char *nmsp[]){
/* xmlns属性(XML名前空間(ネームスペース))に必要なデータをリスト構造に入れておく --------------------S
(データは何件あるかわからないのでリスト構造で動的に確保する)
*/
ns_ptr = &st_dat; /* リスト構造スタート位置のアドレスを設定 */
ns_ptr->next = NULL; /* リスト構造最初のnextにNULLを設定 */
char *pref,*nsp,*cop;
const char *delim = ",";
/* 引数で受け取ったxmlns属性(XML名前空間(ネームスペース))配列の要素数取得 */
int count;
for(count=0;nmsp[count]!=NULL;count++){}
count--;
int i;
for(i=0;i<count;i++){
/* 構造体のメモリーを確保 */
new_ptr = malloc(sizeof(struct XmlNs_Dat));
if(new_ptr == NULL){
printf("メモリを確保出来ない");
exit(1);
}
/* 文字列分割(カンマ区切り) ----------S*/
cop = malloc(strlen(nmsp[i])+1);
strcpy(cop,nmsp[i]);
pref = strtok(cop,delim);
nsp = strtok(NULL,delim);
#ifdef DEBUG1
printf("文字列分割(カンマ区切り) ----------S\n");
printf("DEBUG------strlen(xstr_nsp[i])+1 %d\n",strlen(nmsp[i])+1);
printf("DEBUG------cop %s\n",cop);
printf("DEBUG------pref %s\n",pref);
printf("DEBUG------nsp %s\n",nsp);
printf("文字列分割(カンマ区切り) ----------E\n");
#endif
/* 文字列分割(カンマ区切り) ----------E*/
new_ptr->prefixName = pref; /* プレフィックス名を格納 */
new_ptr->nameSpace = nsp; /* ネームスペースを格納 */
ns_ptr->next = new_ptr; /* 今データを入れた構造体を「next」(次の)ポインタに入れる */
new_ptr->next = NULL; /* 次のためにnextクリアしておく */
ns_ptr = new_ptr; /* */
}
ns_ptr = st_dat.next; /* 開始位置を設定 */
#ifdef DEBUG1
/*** リストの表示 ***/
printf("xmlns属性(XML名前空間(ネームスペース))リスト表示--------S\n");
while (ns_ptr != NULL) {
printf("DEBUG------ns_ptr->prefixName=%s\n",ns_ptr->prefixName);
printf("DEBUG------ns_ptr->nameSpace=%s\n",ns_ptr->nameSpace);
ns_ptr = ns_ptr->next;
}
printf("xmlns属性(XML名前空間(ネームスペース))リスト表示--------E\n");
#endif
/* xmlns属性(XML名前空間(ネームスペース))に必要なデータをリスト構造に入れておく --------------------E
*/
/* XML Xpathに必要なデータをリスト構造に入れておく ----------------------------------------------S
(データは何件あるかわからないのでリスト構造で動的に確保する)
*/
xpt_ptr = &xptSt_dat; /* リスト構造スタート位置のアドレスを設定 */
xpt_ptr->next = NULL; /* リスト構造最初のnextにNULLを設定 */
/* 引数で受け取ったXpath配列の要素数取得 */
int count_xpt;
for(count_xpt=0;xpat[count_xpt]!=NULL;count_xpt++){}
count_xpt--;
int h;
for(h=0;h<count_xpt;h++){
/* 構造体のメモリーを確保 */
xptNew_ptr = malloc(sizeof(struct XmlXp_Dat));
if(xptNew_ptr == NULL){
printf("メモリを確保出来ない");
exit(1);
}
xptNew_ptr->xpathName = xpat[h]; /* Xpathを格納 */
xpt_ptr->next = xptNew_ptr; /* 今データを入れた構造体を「next」(次の)ポインタに入れる */
xptNew_ptr->next = NULL; /* 次のためにnextクリアしておく */
xpt_ptr = xptNew_ptr; /* */
}
xpt_ptr = xptSt_dat.next; /* 開始位置を設定 */
#ifdef DEBUG1
/*** リストの表示 ***/
printf("XML Xpathリスト表示--------------------S\n");
while (xpt_ptr != NULL) {
printf("DEBUG------xpt_ptr->xpathName=%s\n",xpt_ptr->xpathName);
xpt_ptr = xpt_ptr->next;
}
printf("XML Xpathリスト表示--------------------E\n");
#endif
/* XML Xpathに必要なデータをリスト構造に入れておく ----------------------------------------------E
*/
/* */
xml_CSV_Get_execute(opt, input_file);
return(0);
}
/*
--------------------------------------------------------------------------------------------------------
メイン処理(リスト構造体に格納したデータからXpathを取得する)
--------------------------------------------------------------------------------------------------------
*/
int xml_CSV_Get_execute(int opt, char *input_file){
xmlDocPtr doc;
xmlNodePtr root_element = NULL;
/* 標準入力からXMLデータを取得(パイプ)-----------------------------------S
*/
char *buf;
char *buf2;
int r=2;
if(opt == 2){
#ifdef DEBUG1
printf("-ZZZZZZZ- %d\n",sizeof(stdin));
#endif
buf = (char *)calloc(READ_SIZE,sizeof(char));
buf2 = (char *)calloc(READ_SIZE,sizeof(char));
while (fgets(buf,READ_SIZE,stdin) != NULL){
#ifdef DEBUG1
printf("-READ_SIZE buf--------- %d\n",sizeof(buf));
printf("-READ_SIZE buf2--------- %d\n",sizeof(buf2));
#endif
/* 容量が足りなくなったら再確保 */
buf2 = (char *)realloc(buf2,READ_SIZE * r );
#ifdef DEBUG1
printf("--------- %s",buf);
#endif
/* 1行又は指定バイト(4096)単位で読み込んだデータを蓄積 */
strcat(buf2,buf);
r++;
}
input_file = buf2;
#ifdef DEBUG1
printf("-@@@@@@- %s",input_file);
printf("DEBUG------入力XMLデータ------\n %s\n",input_file);
#endif
}
/* 標準入力からXMLデータを取得(パイプ)-----------------------------------E
*/
/* XMLメモリ読み込み-xmlReadMemory----------------------------------------S
【---メモ---】
メモリ上のバッファからXMLを読込んで、xmlDoc構造体を生成する。
XMLデータは改行されていても改行されていなくてもよい。
   【実行方法】
./xml_CSV "`cat tokusyu-3.xml`" 又は cat tokusyu-3.xml|./xml_CSV
*/
if(opt == 0 || opt == 2){
int fsize = strlen(input_file);
#ifdef DEBUG1
printf("DEBUG------XMLデータの文字数 %d\n",fsize);
#endif
doc = xmlReadMemory( input_file, fsize,NULL,"utf-8",0 );
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", input_file);
return;
}
}
/* XMLファイル読み込み-xmlReadMemory----------------------------------------E
*/
/* XMLファイル読み込み-xmlReadFile------------------------------------------S
【---メモ---】
XMLファイルを引数に指定する場合
*/
if(opt == 1){
doc = xmlReadFile(input_file, NULL, 0);
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", input_file);
return;
}
}
/* XMLファイル読み込み-xmlReadFile------------------------------------------E
*/
/*
【---メモ---】
   xmlns属性(XML名前空間(ネームスペース))が設定されてしまっている場合
   「<Report xmlns="http://xml.kishou.go.jp/jmaxml1/" xmlns:jmx="http://xml.kishou.go.jp/jmaxml1/">」
   のような場合はネームスペースを登録する必要がある。
   ↓
   xmlXPathRegisterNs(xpath_context, BAD_CAST "x",BAD_CAST "http://xml.kishou.go.jp/jmaxml1/");
   ↓
   http://xml.kishou.go.jp/jmaxml1/ は 「x」に置き換える
*/
/* getElementTagName-----------------------------------------S
*/
ns_ptr = st_dat.next; /* ネームスペース用構造体の開始位置を設定 */
xpt_ptr = xptSt_dat.next; /* Xpath用構造体の開始位置を設定 */
/* 個別にXPATHを設定して取得 */
execute_xpath_get(doc, "/descendant::*[name()='Title']",ns_ptr);
/* 個別にXPATHを設定して取得 */
execute_xpath_get(doc, "/x:Report/x:Control/x:Status",ns_ptr);
/* リストに登録したもの全てを取得 */
execute_xpath_ListGet(doc,xpt_ptr,ns_ptr);
/* getElementTagName-----------------------------------------E
*/
/* 終了処理-----------------------------------------S
*/
/* メモリ上のxmlDocを開放 */
xmlFreeDoc(doc);
/* libxmlパーサを開放 */
xmlCleanupParser();
if(opt == 2){
free(buf);
free(buf2);
}
/* 終了処理-----------------------------------------E
*/
return 0;
}
/*
----------------------------------------------------------------------
文字の置換
----------------------------------------------------------------------
*/
void replace_char(char *str)
{
/*
\n:FL:改行
\r:CR:復帰
\0:0x00:文字が空
*/
int i;
for (i = strlen(str) - 1; 0 <= i; i--) {
if ((str[i] == '\r') ||
(str[i] == '\n') ||
(str[i] == ' ')) {
/*空文字に置き換える*/
str[i] = '\0';
}
else {
break;
}
}
}
/*
----------------------------------------------------------------------
----------------------------------------------------------------------
*/
void print_attr(xmlAttrPtr attr, FILE *output)
{
xmlAttrPtr cur_attr = NULL;
for (cur_attr = attr; cur_attr; cur_attr = cur_attr->next) {
fprintf(output, "attr %s=%s\n", attr->name, attr->children->content);
}
}
/*
----------------------------------------------------------------------
取得したXpathの情報表示
----------------------------------------------------------------------
*/
void print_xpath_nodes(xmlNodeSetPtr nodes, FILE *output)
{
xmlNodePtr cur;
int size;
int i;
char *content;
char buf[CONTENT_SIZE];
size = (nodes) ? nodes->nodeNr : 0;
/* fprintf(output, "Result (%d nodes):\n", size);*/
for(i = 0; i < size; ++i) {
if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns;
ns = (xmlNsPtr)nodes->nodeTab[i];
cur = (xmlNodePtr)ns->next;
#ifdef DEBUG1
if(cur->ns) {
fprintf(output,
"= namespace \"%s\"=\"%s\" for node %s:%s",
ns->prefix,
ns->href, cur->ns->href, cur->name);
}
else {
fprintf(output,
"= namespace \"%s\"=\"%s\" for node %s",
ns->prefix, ns->href, cur->name);
}
#endif
}
else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
cur = nodes->nodeTab[i];
#ifdef DEBUG1
if(cur->ns) {
fprintf(output,
"= element node \"%s:%s\"",
cur->ns->href, cur->name);
}
else {
fprintf(output, "= element node \"%s\"",
cur->name);
}
#endif
}
else {
cur = nodes->nodeTab[i];
#ifdef DEBUG1
fprintf(output, "= node \"%s\": type %d: ", cur->name, cur->type);
#endif
}
content = cur->children->content;
if (NULL != content) {
strcpy(buf, content);
replace_char(buf);
fprintf(output, " content :%s:%s\n", cur->name,buf);
}
else {
fprintf(output, " content (null)\n");
}
print_attr(cur->properties, output);
}
}
/*
----------------------------------------------------------------------
Xpath取得の実行(単体)
----------------------------------------------------------------------
*/
int execute_xpath_get(xmlDocPtr doc, xmlChar *xpath_expr ,struct XmlNs_Dat *lns)
{
xmlXPathContextPtr xpath_context;
xmlXPathObjectPtr xpath_obj;
printf("---- XPath Get %s\n", xpath_expr);
/* xmlXPathNewContext */
xpath_context = xmlXPathNewContext(doc);
if(xpath_context == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return -1;
}
/*
* 名前空間(ネームスペース)の設定
*/
/*
xmlXPathRegisterNs(xpath_context, BAD_CAST "x",BAD_CAST "http://xml.kishou.go.jp/jmaxml1/");
xmlXPathRegisterNs(xpath_context, BAD_CAST "xh",BAD_CAST "http://xml.kishou.go.jp/jmaxml1/informationBasis1/");
xmlXPathRegisterNs(xpath_context, BAD_CAST "xb",BAD_CAST "http://xml.kishou.go.jp/jmaxml1/body/meteorology1/");
*/
while (lns != NULL) { /* 次ポインタがNULLまで処理 */
#ifdef DEBUG1
printf("名前空間(ネームスペース)の設定----------------S\n");
printf("DEBUG------lns->prefixName=%s\n",lns->prefixName);
printf("DEBUG------lns->nameSpace=%s\n",lns->nameSpace);
printf("名前空間(ネームスペース)の設定----------------E\n");
#endif
/* lns->prefixName:プレフィックス名、lns->nameSpace:ネームスペースを登録 */
xmlXPathRegisterNs(xpath_context, BAD_CAST lns->prefixName,BAD_CAST lns->nameSpace);
lns = lns->next;
}
/* xmlXPathEvalExpressionで取得 */
xpath_obj = xmlXPathEvalExpression(xpath_expr, xpath_context);
if(xpath_obj == NULL) {
fprintf(stderr,
"Error: unable to evaluate xpath expression \"%s\"\n",
xpath_expr);
xmlXPathFreeContext(xpath_context);
xmlFreeDoc(doc);
return -1;
}
/* Print results */
print_xpath_nodes(xpath_obj->nodesetval, stdout);
/* メモリ解放 */
xmlXPathFreeObject(xpath_obj);
xmlXPathFreeContext(xpath_context);
}
/*
----------------------------------------------------------------------
Xpath取得の実行(リストデータ内の全て)
----------------------------------------------------------------------
*/
int execute_xpath_ListGet(xmlDocPtr doc, struct XmlXp_Dat *xpt,struct XmlNs_Dat *lns)
{
xmlXPathContextPtr xpath_context;
xmlXPathObjectPtr xpath_obj;
printf("---- XPath ListGet \n");
/* xmlXPathNewContext */
xpath_context = xmlXPathNewContext(doc);
if(xpath_context == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return -1;
}
/*
* 名前空間(ネームスペース)の設定--------------------------------------------
*/
while (lns != NULL) { /* 次ポインタがNULLまで処理 */
#ifdef DEBUG1
printf("名前空間(ネームスペース)の設定----------------S\n");
printf("DEBUG------lns->prefixName=%s\n",lns->prefixName);
printf("DEBUG------lns->nameSpace=%s\n",lns->nameSpace);
printf("名前空間(ネームスペース)の設定----------------E\n");
#endif
/* lns->prefixName:プレフィックス名、lns->nameSpace:ネームスペースを登録 */
xmlXPathRegisterNs(xpath_context, BAD_CAST lns->prefixName,BAD_CAST lns->nameSpace);
lns = lns->next;
}
/*
* xmlXPathEvalExpressionで取得----------------------------------------------
*/
while (xpt != NULL) { /* 次ポインタがNULLまで処理 */
xpath_obj = xmlXPathEvalExpression(xpt->xpathName, xpath_context);
if(xpath_obj == NULL) {
fprintf(stderr,
"Error: unable to evaluate xpath expression \"%s\"\n",
xpt->xpathName);
xmlXPathFreeContext(xpath_context);
xmlFreeDoc(doc);
return -1;
}
/* Print results */
print_xpath_nodes(xpath_obj->nodesetval, stdout);
xpt = xpt->next;
}
/* メモリ解放 */
xmlXPathFreeObject(xpath_obj);
xmlXPathFreeContext(xpath_context);
}
/*
----------------------------------------------------------------------
DEBUG用関数
----------------------------------------------------------------------
*/
int test(char *aa[])
{
/* 配列数確認 */
int j=0;
for(j=0;NULL!=aa[j];j++){}
j--;
int i=0;
printf("TEST CODE DEBUG--------------配列数-----%d\n",j);
for(i=0; i < j ; i++){
printf("TEST CODE DEBUG------%s\n",aa[i]);
}
}
/*
----------------------------------------------------------------------
正規表現関数
引数:
char *str :検索対象文字列
char *regexstr :正規表現文字列
戻り値:
int 0:マッチあり 1:マッチなし
REG_EXTENDED
regex に POSIX 拡張正規表現を使用する。もしこのフラグが設定されない場合、POSIX 標準正規表現が使われる。
REG_ICASE
大文字小文字の違いを無視する。
REG_NOSUB
このフラグを設定してコンパイルされたパターンバッファが regexec の引数に指定されると、パラメータ nmatch, pmatch が無視される。
REG_NEWLINE
全ての文字にマッチするオペレータに改行をマッチさせない。
----------------------------------------------------------------------
*/
int regex_seek(char *str, char *regexstr){
regex_t regbuf;
size_t nmatch = 3;
regmatch_t pmatch[nmatch];
int len=0;
char tmp[100];
int ret=1;
memset(tmp, '\0', sizeof(tmp));
/* 正規表現のコンパイルを行なう */
if (regcomp(&regbuf, regexstr, REG_EXTENDED|REG_NEWLINE) != 0) {
printf("regex compile failed.\n");
exit(1);
}
/* 正規表現による検索を実行する */
if (regexec(&regbuf, str, nmatch, pmatch, 0) != 0) {
#ifdef DEBUG1
printf("No match.\n");
#endif
}
else {
#ifdef DEBUG1
printf("nmatch!! \n");
/* マッチした文字列は regmatch_t 構造体の配列にその位置が記録されている
rm_so:マッチした文字列の先頭へのインデックス
rm_eo:マッチした文字列の次の文字へのインデックス
*/
len = pmatch[0].rm_eo - pmatch[0].rm_so;
printf("先頭:%d 次:%d LEN:%d\n",pmatch[0].rm_so,pmatch[0].rm_eo,len);
strncpy(tmp, &str[pmatch[0].rm_so], len);
printf("マッチ文字:%s\n",tmp);
#endif
ret=0;
}
/* 正規表現パターンバッファを解放 */
regfree(&regbuf);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment