8 #include <libxml/xmlstring.h>
9 #include <libxml/xmlreader.h>
10 #include <libxml/hash.h>
12 #include "nominatim.h"
16 typedef enum { FILETYPE_NONE, FILETYPE_STRUCTUREDV0P1 } filetypes_t;
17 typedef enum { FILEMODE_NONE, FILEMODE_ADD, FILEMODE_UPDATE, FILEMODE_DELETE } filemodes_t;
19 #define MAX_FEATUREADDRESS 5000
20 #define MAX_FEATURENAMES 10000
21 #define MAX_FEATUREEXTRATAGS 10000
22 #define MAX_FEATURENAMESTRING 1000000
23 #define MAX_FEATUREEXTRATAGSTRING 500000
25 struct feature_address
50 xmlChar * rankAddress;
52 xmlChar * countryCode;
53 xmlChar * parentPlaceID;
57 xmlChar * houseNumber;
61 int fileType = FILETYPE_NONE;
62 int fileMode = FILEMODE_ADD;
64 struct feature_address featureAddress[MAX_FEATUREADDRESS];
65 struct feature_tag featureName[MAX_FEATURENAMES];
66 struct feature_tag featureExtraTag[MAX_FEATUREEXTRATAGS];
67 struct feature feature;
68 int featureAddressLines = 0;
69 int featureNameLines = 0;
70 int featureExtraTagLines = 0;
72 xmlHashTablePtr partionTableTagsHash;
73 xmlHashTablePtr partionTableTagsHashDelete;
74 char featureNameString[MAX_FEATURENAMESTRING];
75 char featureExtraTagString[MAX_FEATUREEXTRATAGSTRING];
77 void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
83 if (fileType == FILETYPE_NONE)
85 // Potential to handle other file types in the future / versions
86 if (xmlStrEqual(name, BAD_CAST "osmStructured"))
88 value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version");
89 version = strtof(value, NULL);
92 if (version == (float)0.1)
94 fileType = FILETYPE_STRUCTUREDV0P1;
95 fileMode = FILEMODE_ADD;
99 fprintf( stderr, "Unknown osmStructured version %f (%s)\n", version, value );
105 fprintf( stderr, "Unknown XML document type: %s\n", name );
111 if (xmlStrEqual(name, BAD_CAST "add"))
113 fileMode = FILEMODE_ADD;
116 if (xmlStrEqual(name, BAD_CAST "update"))
118 fileMode = FILEMODE_UPDATE;
121 if (xmlStrEqual(name, BAD_CAST "delete"))
123 fileMode = FILEMODE_DELETE;
126 if (fileMode == FILEMODE_NONE)
128 fprintf( stderr, "Unknown import mode in: %s\n", name );
132 if (xmlStrEqual(name, BAD_CAST "feature"))
134 feature.placeID = xmlTextReaderGetAttribute(reader, BAD_CAST "place_id");
135 feature.type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
136 feature.id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
137 feature.key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
138 feature.value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
139 feature.rankAddress = xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
140 feature.rankSearch = xmlTextReaderGetAttribute(reader, BAD_CAST "importance");
142 feature.parentPlaceID = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_place_id");
144 if (strlen(feature.parentPlaceID) == 0)
146 xmlFree(feature.parentPlaceID);
147 feature.parentPlaceID = NULL;
150 feature.parentType = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_type");
151 feature.parentID = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_id");
153 feature.countryCode = NULL;
154 feature.adminLevel = NULL;
155 feature.houseNumber = NULL;
156 feature.geometry = NULL;
157 featureAddressLines = 0;
158 featureNameLines = 0;
159 featureExtraTagLines = 0;
163 if (xmlStrEqual(name, BAD_CAST "names")) return;
164 if (xmlStrEqual(name, BAD_CAST "name"))
166 if (featureNameLines < MAX_FEATURENAMES)
168 featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
169 featureName[featureNameLines].value = xmlTextReaderReadString(reader);
174 fprintf( stderr, "Too many name elements (%s%s)\n", feature.type, feature.id);
179 if (xmlStrEqual(name, BAD_CAST "tags")) return;
180 if (xmlStrEqual(name, BAD_CAST "tag"))
182 if (featureExtraTagLines < MAX_FEATUREEXTRATAGS)
184 featureExtraTag[featureExtraTagLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
185 featureExtraTag[featureExtraTagLines].value = xmlTextReaderReadString(reader);
186 featureExtraTagLines++;
190 fprintf( stderr, "Too many extra tag elements (%s%s)\n", feature.type, feature.id);
195 if (xmlStrEqual(name, BAD_CAST "osmGeometry"))
197 feature.geometry = xmlTextReaderReadString(reader);
200 if (xmlStrEqual(name, BAD_CAST "adminLevel"))
202 feature.adminLevel = xmlTextReaderReadString(reader);
205 if (xmlStrEqual(name, BAD_CAST "countryCode"))
207 feature.countryCode = xmlTextReaderReadString(reader);
210 if (xmlStrEqual(name, BAD_CAST "houseNumber"))
212 feature.houseNumber = xmlTextReaderReadString(reader);
215 if (xmlStrEqual(name, BAD_CAST "address"))
217 featureAddressLines = 0;
221 if (xmlStrEqual(name, BAD_CAST "continent"))
225 else if (xmlStrEqual(name, BAD_CAST "sea"))
229 else if (xmlStrEqual(name, BAD_CAST "country"))
233 else if (xmlStrEqual(name, BAD_CAST "state"))
237 else if (xmlStrEqual(name, BAD_CAST "county"))
241 else if (xmlStrEqual(name, BAD_CAST "city"))
245 else if (xmlStrEqual(name, BAD_CAST "town"))
249 else if (xmlStrEqual(name, BAD_CAST "village"))
253 else if (xmlStrEqual(name, BAD_CAST "unknown"))
257 else if (xmlStrEqual(name, BAD_CAST "suburb"))
261 else if (xmlStrEqual(name, BAD_CAST "postcode"))
265 else if (xmlStrEqual(name, BAD_CAST "neighborhood"))
269 else if (xmlStrEqual(name, BAD_CAST "street"))
273 else if (xmlStrEqual(name, BAD_CAST "access"))
277 else if (xmlStrEqual(name, BAD_CAST "building"))
281 else if (xmlStrEqual(name, BAD_CAST "other"))
287 if (featureAddressLines < MAX_FEATUREADDRESS)
289 value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
292 fprintf( stderr, "Address element missing rank\n");
295 featureAddress[featureAddressLines].rankAddress = atoi(value);
298 value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "isaddress");
301 fprintf( stderr, "Address element missing rank\n");
304 if (*value == 't') strcpy(featureAddress[featureAddressLines].isAddress, "t");
305 else strcpy(featureAddress[featureAddressLines].isAddress, "f");
308 featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
309 featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
310 featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
311 featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
312 featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
314 featureAddressLines++;
318 fprintf( stderr, "Too many address elements (%s%s)\n", feature.type, feature.id);
324 fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
327 void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
330 const char * paramValues[14];
332 char * partionQueryName;
333 int i, namePos, lineTypeLen, lineValueLen;
335 if (xmlStrEqual(name, BAD_CAST "feature"))
338 if (featureCount % 1000 == 0) printf("feature %i(k)\n", featureCount/1000);
340 if (fileMode == FILEMODE_ADD)
342 resPlaceID = PQexecPrepared(conn, "get_new_place_id", 0, NULL, NULL, NULL, 0);
343 if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
345 fprintf(stderr, "get_place_id: INSERT failed: %s", PQerrorMessage(conn));
352 paramValues[0] = (const char *)feature.type;
353 paramValues[1] = (const char *)feature.id;
354 paramValues[2] = (const char *)feature.key;
355 paramValues[3] = (const char *)feature.value;
356 resPlaceID = PQexecPrepared(conn, "get_new_place_id", 4, paramValues, NULL, NULL, 0);
357 if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
359 fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
365 place_id = (char *)feature.placeID;
367 if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE || fileMode == FILEMODE_ADD)
369 paramValues[0] = (const char *)place_id;
370 res = PQexecPrepared(conn, "placex_delete", 1, paramValues, NULL, NULL, 0);
371 if (PQresultStatus(res) != PGRES_COMMAND_OK)
373 fprintf(stderr, "placex_delete: DELETE failed: %s", PQerrorMessage(conn));
379 res = PQexecPrepared(conn, "search_name_delete", 1, paramValues, NULL, NULL, 0);
380 if (PQresultStatus(res) != PGRES_COMMAND_OK)
382 fprintf(stderr, "search_name_delete: DELETE failed: %s", PQerrorMessage(conn));
388 res = PQexecPrepared(conn, "place_addressline_delete", 1, paramValues, NULL, NULL, 0);
389 if (PQresultStatus(res) != PGRES_COMMAND_OK)
391 fprintf(stderr, "place_addressline_delete: DELETE failed: %s", PQerrorMessage(conn));
397 partionQueryName = xmlHashLookup2(partionTableTagsHashDelete, feature.key, feature.value);
398 if (partionQueryName)
400 res = PQexecPrepared(conn, partionQueryName, 1, paramValues, NULL, NULL, 0);
401 if (PQresultStatus(res) != PGRES_COMMAND_OK)
403 fprintf(stderr, "%s: DELETE failed: %s", partionQueryName, PQerrorMessage(conn));
411 if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_ADD)
413 // Insert into placex
414 paramValues[0] = (const char *)place_id;
415 paramValues[1] = (const char *)feature.type;
416 paramValues[2] = (const char *)feature.id;
417 paramValues[3] = (const char *)feature.key;
418 paramValues[4] = (const char *)feature.value;
420 featureNameString[0] = 0;
421 if (featureNameLines)
426 for (i = 0; i < featureNameLines; i++)
428 lineTypeLen = (int)strlen((char *) featureName[i].type);
429 lineValueLen = (int)strlen((char *) featureName[i].value);
430 if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATURENAMESTRING)
432 fprintf(stderr, "feature name too long: %s", (const char *)featureName[i].value);
435 if (namePos) strcpy(featureNameString+(namePos++), ",");
436 strcpy(featureNameString+(namePos++), "\"");
437 strcpy(featureNameString+namePos, (char*) featureName[i].type);
438 namePos += lineTypeLen;
439 strcpy(featureNameString+namePos, "\"=>\"");
441 strcpy(featureNameString+namePos, (char *) featureName[i].value);
442 namePos += lineValueLen;
443 strcpy(featureNameString+(namePos++), "\"");
446 paramValues[5] = (const char *)featureNameString;
448 paramValues[6] = (const char *)feature.countryCode;
450 featureExtraTagString[0] = 0;
451 if (featureExtraTagLines)
456 for (i = 0; i < featureExtraTagLines; i++)
458 lineTypeLen = strlen((char *) featureExtraTag[i].type);
459 lineValueLen = strlen((char *) featureExtraTag[i].value);
460 if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATUREEXTRATAGSTRING)
462 fprintf(stderr, "feature extra tag too long: %s", (const char *)featureExtraTag[i].value);
465 if (namePos) strcpy(featureExtraTagString+(namePos++),",");
466 strcpy(featureExtraTagString+(namePos++), "\"");
467 strcpy(featureExtraTagString+namePos, (char *) featureExtraTag[i].type);
468 namePos += lineTypeLen;
469 strcpy(featureExtraTagString+namePos, "\"=>\"");
471 strcpy(featureExtraTagString+namePos, (char *) featureExtraTag[i].value);
472 namePos += lineValueLen;
473 strcpy(featureExtraTagString+(namePos++), "\"");
476 paramValues[7] = (const char *)featureExtraTagString;
478 if (strlen(feature.parentPlaceID) == 0)
479 paramValues[8] = "0";
481 paramValues[8] = (const char *)feature.parentPlaceID;
483 paramValues[9] = (const char *)feature.adminLevel;
484 paramValues[10] = (const char *)feature.houseNumber;
485 paramValues[11] = (const char *)feature.rankAddress;
486 paramValues[12] = (const char *)feature.rankSearch;
487 paramValues[13] = (const char *)feature.geometry;
488 if (strlen(paramValues[3]))
490 res = PQexecPrepared(conn, "placex_insert", 14, paramValues, NULL, NULL, 0);
491 if (PQresultStatus(res) != PGRES_COMMAND_OK)
493 fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
494 fprintf(stderr, "index_placex: INSERT failed: %s %s %s", paramValues[0], paramValues[1], paramValues[2]);
501 for (i = 0; i < featureAddressLines; i++)
503 // insert into place_address
504 paramValues[0] = (const char *)place_id;
505 paramValues[1] = (const char *)featureAddress[i].distance;
506 paramValues[2] = (const char *)featureAddress[i].type;
507 paramValues[3] = (const char *)featureAddress[i].id;
508 paramValues[4] = (const char *)featureAddress[i].key;
509 paramValues[5] = (const char *)featureAddress[i].value;
510 paramValues[6] = (const char *)featureAddress[i].isAddress;
511 res = PQexecPrepared(conn, "place_addressline_insert", 7, paramValues, NULL, NULL, 0);
512 if (PQresultStatus(res) != PGRES_COMMAND_OK)
514 fprintf(stderr, "place_addressline_insert: INSERT failed: %s", PQerrorMessage(conn));
520 xmlFree(featureAddress[i].type);
521 xmlFree(featureAddress[i].id);
522 xmlFree(featureAddress[i].key);
523 xmlFree(featureAddress[i].value);
524 xmlFree(featureAddress[i].distance);
527 if (featureNameLines)
529 paramValues[0] = (const char *)place_id;
530 res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
531 if (PQresultStatus(res) != PGRES_COMMAND_OK)
533 fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
540 partionQueryName = xmlHashLookup2(partionTableTagsHash, feature.key, feature.value);
541 if (partionQueryName)
543 // insert into partition table
544 paramValues[0] = (const char *)place_id;
545 paramValues[1] = (const char *)feature.geometry;
546 res = PQexecPrepared(conn, partionQueryName, 2, paramValues, NULL, NULL, 0);
547 if (PQresultStatus(res) != PGRES_COMMAND_OK)
549 fprintf(stderr, "%s: INSERT failed: %s", partionQueryName, PQerrorMessage(conn));
559 for (i = 0; i < featureAddressLines; i++)
561 xmlFree(featureAddress[i].type);
562 xmlFree(featureAddress[i].id);
563 xmlFree(featureAddress[i].key);
564 xmlFree(featureAddress[i].value);
565 xmlFree(featureAddress[i].distance);
569 xmlFree(feature.placeID);
570 xmlFree(feature.type);
572 xmlFree(feature.key);
573 xmlFree(feature.value);
574 xmlFree(feature.rankAddress);
575 xmlFree(feature.rankSearch);
576 if (feature.parentPlaceID) xmlFree(feature.parentPlaceID);
577 if (feature.parentType) xmlFree(feature.parentType);
578 if (feature.parentID) xmlFree(feature.parentID);
579 // if (feature.name) xmlFree(feature.name);
580 if (feature.countryCode) xmlFree(feature.countryCode);
581 if (feature.adminLevel) xmlFree(feature.adminLevel);
582 if (feature.houseNumber) xmlFree(feature.houseNumber);
583 if (feature.geometry) xmlFree(feature.geometry);
585 // PQclear(resPlaceID);
589 static void processNode(xmlTextReaderPtr reader)
592 name = xmlTextReaderName(reader);
595 name = xmlStrdup(BAD_CAST "--");
598 switch (xmlTextReaderNodeType(reader))
600 case XML_READER_TYPE_ELEMENT:
601 StartElement(reader, name);
602 if (xmlTextReaderIsEmptyElement(reader))
603 EndElement(reader, name); /* No end_element for self closing tags! */
605 case XML_READER_TYPE_END_ELEMENT:
606 EndElement(reader, name);
608 case XML_READER_TYPE_TEXT:
609 case XML_READER_TYPE_CDATA:
610 case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
614 fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
621 int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename)
623 xmlTextReaderPtr reader;
626 FILE * partionTagsFile;
627 char * partionQueryName;
628 char partionQuerySQL[1024];
630 conn = PQconnectdb(conninfo);
631 if (PQstatus(conn) != CONNECTION_OK)
633 fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
637 partionTableTagsHash = xmlHashCreate(200);
638 partionTableTagsHashDelete = xmlHashCreate(200);
640 partionTagsFile = fopen(partionTagsFilename, "rt");
641 if (!partionTagsFile)
643 fprintf(stderr, "Unable to read partition tags file: %s\n", partionTagsFilename);
647 char buffer[1024], osmkey[256], osmvalue[256];
649 while (fgets(buffer, sizeof(buffer), partionTagsFile) != NULL)
651 fields = sscanf( buffer, "%23s %63s", osmkey, osmvalue );
653 if ( fields <= 0 ) continue;
657 fprintf( stderr, "Error partition file\n");
660 partionQueryName = malloc(strlen("partition_insert_")+strlen(osmkey)+strlen(osmvalue)+2);
661 strcpy(partionQueryName, "partition_insert_");
662 strcat(partionQueryName, osmkey);
663 strcat(partionQueryName, "_");
664 strcat(partionQueryName, osmvalue);
666 strcpy(partionQuerySQL, "insert into place_classtype_");
667 strcat(partionQuerySQL, osmkey);
668 strcat(partionQuerySQL, "_");
669 strcat(partionQuerySQL, osmvalue);
670 strcat(partionQuerySQL, " (place_id, centroid) values ($1, ST_Centroid(st_setsrid($2, 4326)))");
672 res = PQprepare(conn, partionQueryName, partionQuerySQL, 2, NULL);
673 if (PQresultStatus(res) != PGRES_COMMAND_OK)
675 fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
679 xmlHashAddEntry2(partionTableTagsHash, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
681 partionQueryName = malloc(strlen("partition_delete_")+strlen(osmkey)+strlen(osmvalue)+2);
682 strcpy(partionQueryName, "partition_delete_");
683 strcat(partionQueryName, osmkey);
684 strcat(partionQueryName, "_");
685 strcat(partionQueryName, osmvalue);
687 strcpy(partionQuerySQL, "delete from place_classtype_");
688 strcat(partionQuerySQL, osmkey);
689 strcat(partionQuerySQL, "_");
690 strcat(partionQuerySQL, osmvalue);
691 strcat(partionQuerySQL, " where place_id = $1::integer");
693 res = PQprepare(conn, partionQueryName, partionQuerySQL, 1, NULL);
694 if (PQresultStatus(res) != PGRES_COMMAND_OK)
696 fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
700 xmlHashAddEntry2(partionTableTagsHashDelete, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
703 res = PQprepare(conn, "get_new_place_id",
704 "select nextval('seq_place')",
706 if (PQresultStatus(res) != PGRES_COMMAND_OK)
708 fprintf(stderr, "Failed to prepare get_new_place_id: %s\n", PQerrorMessage(conn));
712 res = PQprepare(conn, "get_place_id",
713 "select place_id from placex where osm_type = $1 and osm_id = $2 and class = $3 and type = $4",
715 if (PQresultStatus(res) != PGRES_COMMAND_OK)
717 fprintf(stderr, "Failed to prepare get_place_id: %s\n", PQerrorMessage(conn));
721 res = PQprepare(conn, "placex_insert",
722 "insert into placex (place_id,osm_type,osm_id,class,type,name,country_code,extratags,parent_place_id,admin_level,housenumber,rank_address,rank_search,geometry) "
723 "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, st_setsrid($14, 4326))",
725 if (PQresultStatus(res) != PGRES_COMMAND_OK)
727 fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
731 res = PQprepare(conn, "search_name_insert",
732 "insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
733 "select place_id, rank_address, rank_search, country_code, make_keywords(name), "
734 "(select uniq(sort(array_agg(name_vector))) from place_addressline join search_name on "
735 "(address_place_id = search_name.place_id) where place_addressline.place_id = $1 ), st_centroid(geometry) from placex "
736 "where place_id = $1",
738 if (PQresultStatus(res) != PGRES_COMMAND_OK)
740 fprintf(stderr, "Failed to prepare search_name_insert: %s\n", PQerrorMessage(conn));
744 res = PQprepare(conn, "place_addressline_insert",
745 "insert into place_addressline (place_id, address_place_id, fromarea, isaddress, distance, cached_rank_address) "
746 "select $1, place_id, false, $7, $2, rank_address from placex where osm_type = $3 and osm_id = $4 and class = $5 and type = $6",
748 if (PQresultStatus(res) != PGRES_COMMAND_OK)
750 fprintf(stderr, "Failed to prepare place_addressline_insert: %s\n", PQerrorMessage(conn));
754 res = PQprepare(conn, "placex_delete",
755 "delete from placex where place_id = $1",
757 if (PQresultStatus(res) != PGRES_COMMAND_OK)
759 fprintf(stderr, "Failed to prepare placex_delete: %s\n", PQerrorMessage(conn));
763 res = PQprepare(conn, "search_name_delete",
764 "delete from search_name where place_id = $1",
766 if (PQresultStatus(res) != PGRES_COMMAND_OK)
768 fprintf(stderr, "Failed to prepare search_name_delete: %s\n", PQerrorMessage(conn));
772 res = PQprepare(conn, "place_addressline_delete",
773 "delete from place_addressline where place_id = $1",
775 if (PQresultStatus(res) != PGRES_COMMAND_OK)
777 fprintf(stderr, "Failed to prepare place_addressline_delete: %s\n", PQerrorMessage(conn));
783 reader = inputUTF8(filename);
787 fprintf(stderr, "Unable to open %s\n", filename);
791 ret = xmlTextReaderRead(reader);
795 ret = xmlTextReaderRead(reader);
799 fprintf(stderr, "%s : failed to parse\n", filename);
803 xmlFreeTextReader(reader);
804 xmlHashFree(partionTableTagsHash, NULL);
805 xmlHashFree(partionTableTagsHashDelete, NULL);