Large data sets (Expat v2.0.0; compiled cygwin)
"Ben Keitch" <[email protected]>
| Newsgroups | gmane.text.xml.expat.general |
|---|---|
| Message-ID | <[email protected]> |
Can someone help me with this code. It is trying to convert an XML file of book data to tab-deliminated. Should be simple, but it seems to mangle about 200 of the 10000 records I give it. Supplying each record by itself, it works fine. I don't understand why, but not being a C programmer, I dare say I am mangling pointers, or there is a multithread issue I don't understand. here is a typical error: given lines 3380-3383 in a 917682 long XML file (it is well-formed according to xmlwf): <record> <ISBN10>0816044384</ISBN10> <ISBN13>9780816044382</ISBN13> <EAN>9780816044382</EAN> ... </record> the data given to the data handler (and printed to stderr) is: Data: 9780816 Data: 044382 Error : isbn10: 0816044384 isbn: 382 isbn13: 044382 Data: Data: 9780816044382 So in this case, ISBN10 was correct, but ISBN13 only got the last 6 digits on the first call, but managed to get all the data on the third call (the second call gives a blank line! why?) If you give just this XML record to the program, it works fine. Any help greatly appreciated _______________________________________________ Expat-discuss mailing list [email protected] http://mail.libexpat.org/mailman/listinfo/expat-discuss
processfile.c
(application/octet-stream, 6.6 KB)
/*
* Program to take Neilson XML book data
* and select various pieces of essential data.
* The output is in tab deliminated text in a from that the
* COPY command in Postgres can read in from
*
* Author Ben Keitch 13 April 2007
*/
#include <stdio.h>
#include "expat.h"
#include <string.h>
#ifdef XML_LARGE_SIZE
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
#define XML_FMT_INT_MOD "I64"
#else
#define XML_FMT_INT_MOD "l"
#endif
#else
#define XML_FMT_INT_MOD ""
#endif
char temp[BUFSIZ] = "";
struct book {
char isbn[BUFSIZ];
char isbn10[BUFSIZ];
char isbn13[BUFSIZ];
char title[BUFSIZ];
char pub[BUFSIZ];
char price[BUFSIZ];
char format[BUFSIZ];
char pubdate[BUFSIZ];
char name1[BUFSIZ];
char type1[BUFSIZ];
char name2[BUFSIZ];
char type2[BUFSIZ];
char name3[BUFSIZ];
char type3[BUFSIZ];
char name4[BUFSIZ];
char type4[BUFSIZ];
char name5[BUFSIZ];
char type5[BUFSIZ];
char name6[BUFSIZ];
char type6[BUFSIZ];
} abook;
/*
* This is a desperate attempt to get the ISBN-10 code from
* the ISBN-13 code. It seems though that ISBN-13 codes get
* mangled just as oftern as the ISBN-10 code
*/
void ean2isbn(char *ean) {
int multiplier = 10;
int i,chksum=0;
char checkDigit;
static char buf[10] = "0123456789";
for (i=3;i<=11;i++) {
chksum += ((int)ean[i]-48)* multiplier;
multiplier--;
ean[i-3] = ean[i];
}
chksum = 11 - (chksum % 11);
switch(chksum) {
case 10:
checkDigit = 'X';
break;
case 11:
checkDigit = '0';
break;
default:
checkDigit = buf[chksum];
}
ean[9] = checkDigit;
ean[10] = '\0';
}
/* Convert date string from YYYYMMDD to YYYY-MM-DD
* This is really crude, but I don't know how to use pointers!
*/
void convertDate(char *date) {
char tdate[10] = "";
tdate[0]= date[0];
tdate[1]= date[1];
tdate[2]= date[2];
tdate[3]= date[3];
tdate[4]= '-';
tdate[5]= date[4];
tdate[6]= date[5];
tdate[7]= '-';
tdate[8]= date[6];
tdate[9]= date[7];
tdate[10]='\0';
strncpy(date, tdate, 11);
}
/* This puts the data into the structure, depending on the
* name of the tag. Again, crude, using IF statements, but don't know
* any better!
*/
void storeData(char *data, const char *tagname) {
int len;
len = strlen(data);
/* This should work, but ISBN10 sometimes only gives < 10 chars
* WHY?
* instead, use ISBN13 to generate ISBN10 and see if they differ
*/
if(strcmp(tagname, "ISBN10")==0) {
strncpy(abook.isbn10,data,10);
abook.isbn10[10]='\0';
}
if(strcmp(tagname, "ISBN13")==0) {
strncpy(abook.isbn13,data,13);
abook.isbn13[len]='\0';
ean2isbn(data);
/* once we've converted ISBN-13 to ISBN-10 there should be no
* difference (results have been checked using Amazon)
* BUT once in a while ISBN-10 or ISBN-13 gets chomped by Expat
* Hence this code:
*/
if(strcmp(data,abook.isbn10)!=0) {
fprintf(stderr,"Error : isbn10: %s\tisbn: %s\tisbn13: %s\n",
abook.isbn10,data,abook.isbn13);
}
strncpy(abook.isbn,data,10);
abook.isbn[10]='\0';
}
if(strcmp(tagname, "FTS")==0) {
strncpy(abook.title,data, len);
abook.title[len]='\0';
}
if(strcmp(tagname, "PUBN")==0) {
strncpy(abook.pub,data, len);
abook.pub[len]='\0';
}
if(strcmp(tagname, "GBPCCPRRRP")==0) {
strncpy(abook.price,data, len);
abook.price[len]='\0';
}
if(strcmp(tagname, "PFCT")==0) {
strncpy(abook.format,data, len);
abook.format[len]='\0';
}
if(strcmp(tagname, "PUBPD")==0) {
convertDate(data);
strncpy(abook.pubdate,data, len);
abook.pubdate[len]='\0';
}
if(strcmp(tagname, "CNI1")==0) {
strncpy(abook.name1,data, len);
abook.name1[len]='\0';
}
if(strcmp(tagname, "CRT1")==0) {
strncpy(abook.type1,data, len);
abook.type1[len]='\0';
}
if(strcmp(tagname, "CNI2")==0) {
strncpy(abook.name2,data, len);
abook.name2[len]='\0';
}
if(strcmp(tagname, "CRT3")==0) {
strncpy(abook.type2,data, len);
abook.type2[len]='\0';
}
if(strcmp(tagname, "CNI3")==0) {
strncpy(abook.name3,data, len);
abook.name3[len]='\0';
}
if(strcmp(tagname, "CRT3")==0) {
strncpy(abook.type3,data, len);
abook.type3[len]='\0';
}
}
/* This simply copies the data from between the tags (CDATA?) into
* a global string. It chops it down to length, len as instructed in Expat
* docs. Crude, but should work. Even here, printing
* the data straight to STDERR gives chomped results
* WHY!?
* NOTE: we ignore the fact it is a UTF-8 char and not ASCII. The
* input file is ISO-8859-1. Using wchar_t and libexpatw didn't help
* There are no multibyte characters in the input file.
*/
static void XMLCALL myData(void *s, const XML_Char *data, int len) {
strncpy(temp, data, len);
temp[len] = '\0';
fprintf(stderr,"Data: %s\t",temp);
}
/*static void XMLCALL
startElement(void *userData, const char *name, const char **atts){
ISISBN = (strcmp(name, "ISBN10")==0)?true:false;
strncpy(tagname, name, strlen(name));
tagname[strlen(name)]='\0';
}*/
/* When reach the end of the tag
* store the data, according to the tag name
* If we reach the end of the record, print the book details
* and start again
*/
static void XMLCALL
endElement(void *userData, const char *name)
{
storeData(temp, name);
if(strcmp(name, "record")==0) {
printf("%s\t", abook.isbn);
printf("%s\t", abook.price);
printf("%s\t", abook.pubdate);
printf("%s\t", abook.title);
printf("%s\t", abook.pub);
printf("%s\t", abook.format);
printf("%s\t", abook.type1);
printf("%s\t", abook.name1);
printf("%s\t", abook.type2);
printf("%s\t", abook.name2);
printf("%s\t", abook.type3);
printf("%s\t", abook.name3);
/*abook.type4, abook.name4,
abook.type5, abook.name5,
abook.type6, abook.name6,*/
printf("\t\t\t\t\t\t%s\n",abook.isbn13);
} else {
}
}
/*
* This is a copy of the example code given
* with expat - nothing changed except data-handler added
*/
#ifdef AMIGA_SHARED_LIB
#include <proto/expat.h>
int
amiga_main(int argc, char *argv[])
#else
int
main(int argc, char *argv[])
#endif
{
char buf[BUFSIZ];
XML_Parser parser = XML_ParserCreate(NULL);
int done;
int depth = 0;
XML_SetUserData(parser, &depth);
XML_SetEndElementHandler(parser, endElement);
//XML_SetStartElementHandler(parser, startElement);
XML_SetCharacterDataHandler(parser, myData);
do {
size_t len = fread(buf, 1, sizeof(buf), stdin);
done = len < sizeof(buf);
if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
fprintf(stderr,
"%s at line %" XML_FMT_INT_MOD "u\n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
return 1;
}
} while (!done);
XML_ParserFree(parser);
//printf("COPY \"Books\" FROM stdin;\n");
//printf("\\.\n");
return 0;
}
Makefile
(application/octet-stream, 458 B) - not displayed
test.xml
(text/xml, 3 KB)
<record> <ISBN10>0970393113</ISBN10> <ISBN13>9780970393111</ISBN13> <FTS>Farmacist Desk Reference: Encyclopaedia of Whole Food Medicine</FTS> <CR1>A01</CR1> <CRT1>By (author)</CRT1> <CCI1>N</CCI1> <CNI1>Tolman, Don</CNI1> <HMM>300</HMM> <WMM>230</WMM> <EDSL>2nd Revised edition</EDSL> <PFC>BB</PFC> <PFCT>Hardback</PFCT> <PAG>1500</PAG> <IMPN>Trideca Publishing</IMPN> <IMPID>186780</IMPID> <PUBN>Trideca Publishing</PUBN> <PUBID>186780</PUBID> <COP>United States</COP> <NAC1>P</NAC1> <NAT1>Professional & Vocational</NAT1> <OAC1>06</OAC1> <OAT1>Professional and scholarly</OAT1> <BIC11SC1>MXT</BIC11SC1> <BIC11ST1>Traditional medicine & remedies</BIC11ST1> <BIC11SC2>GBC</BIC11SC2> <BIC11ST2>Reference works</BIC11ST2> <DEWS1>DC22</DEWS1> <DEWEY1>615.321</DEWEY1> <BISACC1>HEA010000</BISACC1> <BISACT1>Healthy Living</BISACT1> <BISACC2>SEL000000</BISACC2> <BISACT2>General</BISACT2> <PRODCC>T10.2</PRODCC> <PRODCT>Alternative Therapies & Health</PRODCT> <NBDSD>Presents a compendium of humanities relationship to life and vitality using plant whole foods as preventative and remissive medicine. This title includes 1600 pages of graphics and life impacting information, and ranges from ancient Egyptian to classical Roman times through the Renaissance and into colonial America.</NBDSD> <NBDLD>This book is a definitive compendium of humanities relationship to life and vitality using plant whole foods as preventative and remissive medicine. The "FDR" is a deluxe, high-gloss, hardbound 2 volume boxed set. The "FDR" contains 1600 pages of some of the most stirring graphics and life impacting information that you can imagine and ranges from ancient Egyptian to classical Roman times through the Renaissance and into colonial America. It's a must have.</NBDLD> <NERSL>GB IE</NERSL> <PUBPD>20070509</PUBPD> <PUBSC>04</PUBSC> <PUBST>Active</PUBST> <GBPCCPRA>GB</GBPCCPRA> <GBPCCPRRRP>107.50</GBPCCPRRRP> <GBPCCPRSN>Gazelle Book Services Ltd</GBPCCPRSN> <GBPCCPRC>GBP</GBPCCPRC> <GBPCCPRTOP>0.00</GBPCCPRTOP> <GBPCCPRRRPLT>107.50</GBPCCPRRRPLT> <GBPCCPLCD>20061217</GBPCCPLCD> <GBPCCPRP1TC>Z</GBPCCPRP1TC> <GBPCCPRP1TR>0.0</GBPCCPRP1TR> <GBPCCPRP1TP>107.50</GBPCCPRP1TP> <GBPCCPRP1TOP>0.00</GBPCCPRP1TOP> <USDCCPRA>US</USDCCPRA> <USDCCPRRRP>149.95</USDCCPRRRP> <USDCCPRSN>Ingram</USDCCPRSN> <USDCCPRC>USD</USDCCPRC> <USDCCPRTOP>0.00</USDCCPRTOP> <USDCCPRRRPLT>149.95</USDCCPRRRPLT> <USDCCPRP1TC>Z</USDCCPRP1TC> <USDCCPRP1TR>0.0</USDCCPRP1TR> <USDCCPRP1TP>149.95</USDCCPRP1TP> <USDCCPRP1TOP>0.00</USDCCPRP1TOP> <UKNBDAA>GB</UKNBDAA> <UKNBDASN>Gazelle Book Services Ltd</UKNBDASN> <UKNBDEAD>20070509</UKNBDEAD> <UKNBDPASLCD>20070413</UKNBDPASLCD> <UKNBDPAC>10</UKNBDPAC> <UKNBDPAT>Not yet available</UKNBDPAT> <USNBDAA>US</USNBDAA> <USNBDASN>Ingram</USNBDASN> <USNBDPAC>20</USNBDPAC> <USNBDPAT>Available</USNBDPAT> <UKADN1>Gazelle Book Services Ltd</UKADN1> <UKADI1>89966</UKADI1> <USADN1>Benacquista Publishing</USADN1> <USADI1>9010000000000394743</USADI1> <WSLREXUK>BTB ING</WSLREXUK> </record>