From c7be629d44d4e2be6c8116796714e0042a977885 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 28 Apr 2009 11:12:58 +0200 Subject: Added generic XML -> Python parser The xmlpythonizer module will convert any XML data (xmlNode or xmlDoc) and format it as a Python object. The formatting is defined in it's own XML file. Basic format: The keytype and key attributes defines the key in the Python Dict. The root element will always be a Python Dict structure. The valid key types are: * constant Uses the value in {key} as the key value * string, integer, float Uses a string value from the data XML to be converted to Python. The value set in the key attribute defines an XPath value which points to the data to be used as a Python dict key. Since Python only supports C strings in the C interface for Python dict keys, integer and float will be treated as strings. The valuetype and value attributes are similar to the keys, but with some more features. Valid valuetypes are: * constant The value given in the value attribute will be used in the value in the Python result. * string, integer, float The value given in the value attribute defines the XPath to the data XML, of where to retrieve the value for the given key. The valuetype defines if the data should be understood as a string, integer or float in the Python result. * list:string, list:integer, list:float This does the same as the string, integer or float type, with a tweak. The data will be put into a list. If the XPath given returns multiple nodes, all of them will be added to this list. * dict The dict valuetype is more special. It should not contain any value attribute. On the other hand, it should contain a sub-level of tags. In this way, you can build up a multi dimensional Python dict. Example: ** pythonmap.xml ** ** exampledata.xml ** String value #1 More test data Value1 in list Value2 in list Value3 in list ** C code snippet ** void xmlpythonizer() { xmlDoc *xmlmap = NULL; xmlDoc *xmldata = NULL; ptzMAP *mapping = NULL; PyObject *pythondata = NULL; // Read XML files xmlmap = xmlReadFile("pythonmap.xml", NULL, 0); xmldata = xmlReadFile("exampledata.xml", NULL, 0); // Parse the mapping XML mapping = dmiMAP_ParseMappingXML(xmlmap, "example_map"); // Parse the xmldata into a Python object pythondata = pythonizeXMLdoc(mapping, xmldata); // ..... the program continues to do something useful } The result stored inside the pythondata object should now be something similar to: {'DemoCase': 'XML Pythonizing', 'String1': 'String value #1', 'AttribString1: 1234, 'TestData': {'Value1': 'More test data', 'ValueList': ['Value1 in list','Value2 in list','Value3 in list']} } --- src/xmlpythonizer.c | 522 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 src/xmlpythonizer.c (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c new file mode 100644 index 0000000..92e0d7f --- /dev/null +++ b/src/xmlpythonizer.c @@ -0,0 +1,522 @@ +/* Converts XML docs and nodes to Python dicts and lists by + * using an XML file which describes the Python dict layout + * + * Copyright 2009 David Sommerseth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "dmixml.h" +#include "xmlpythonizer.h" + +ptzMAP *ptzmap_Add(const ptzMAP *chain, + ptzTYPES ktyp, const char *key, + ptzTYPES vtyp, const char *value, + ptzMAP *child) +{ + ptzMAP *ret = NULL; + + assert( (ktyp == ptzCONST) || (ktyp == ptzSTR) || (ktyp == ptzINT) || (ktyp == ptzFLOAT) ); + assert( key != NULL ); + // Make sure that value and child are not used together + assert( ((value == NULL) && child != NULL) || ((value != NULL) && (child == NULL)) ); + + ret = (ptzMAP *) malloc(sizeof(ptzMAP)+2); + assert( ret != NULL ); + memset(ret, 0, sizeof(ptzMAP)+2); + + ret->type_key = ktyp; + ret->key = strdup(key); + + ret->type_value = vtyp; + if( value != NULL ) { + ret->value = strdup(value); + ret->child = NULL; + } else if( child != NULL ) { + ret->value = NULL; + ret->child = child; + } + + if( chain != NULL ) { + ret->next = (ptzMAP *) chain; + } + return ret; +}; + +#define ptzmap_Free(ptr) { ptzmap_Free_func(ptr); ptr = NULL; } +void ptzmap_Free_func(ptzMAP *ptr) +{ + if( ptr == NULL ) { + return; + } + + free(ptr->key); + ptr->key = NULL; + + if( ptr->value != NULL ) { + free(ptr->value); + ptr->value = NULL; + } + + if( ptr->child != NULL ) { + ptzmap_Free(ptr->child); + } + if( ptr->next != NULL ) { + ptzmap_Free(ptr->next); + } + free(ptr); +} + + +#if 1 +// DEBUG FUNCTIONS +static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", + "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", + "ptzDICT", NULL }; + +void indent(int lvl) +{ + int i = 0; + if( lvl == 0 ) { + return; + } + + for( i = 0; i < (lvl * 3); i++ ) { + printf(" "); + } +} + +#define ptzmap_Dump(ptr) { ptzmap_Dump_func(ptr, 0); } +void ptzmap_Dump_func(const ptzMAP *ptr, int level) +{ + if( ptr == NULL ) { + return; + } + + indent(level); printf("key type: (%i) %-13.13s - key: %s\n", + ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); + indent(level); printf("value type: (%i) %-13.13s - value: %s\n", + ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value); + if( ptr->child != NULL ) { + indent(level); printf(" ** CHILD\n"); + ptzmap_Dump_func(ptr->child, level + 1); + indent(level); printf(" ** ---------\n"); + } + if( ptr->next != NULL ) { + printf("\n"); + ptzmap_Dump_func(ptr->next, level); + } +} +#endif // END OF DEBUG FUNCTIONS + +// +// Parser for the XML -> Python mapping XML file +// +// This mappipng XML file describes how the Python result +// should look like and where it should pick the data from +// when later on parsing the dmidecode XML data. +// + +// Valid key and value types for the mapping file +inline ptzTYPES _convert_maptype(const char *str) { + if( strcmp(str, "string") == 0 ) { + return ptzSTR; + } else if( strcmp(str, "constant") == 0 ) { + return ptzCONST; + } else if( strcmp(str, "integer") == 0 ) { + return ptzINT; + } else if( strcmp(str, "float") == 0 ) { + return ptzFLOAT; + } else if( strcmp(str, "list:string") == 0 ) { + return ptzLIST_STR; + } else if( strcmp(str, "list:integer") == 0 ) { + return ptzLIST_INT; + } else if( strcmp(str, "list:float") == 0 ) { + return ptzLIST_FLOAT; + } else if( strcmp(str, "dict") == 0 ) { + return ptzDICT; + } else { + fprintf(stderr, "Unknown field type: %s - defaulting to 'string'\n", str); + return ptzSTR; + } +} + +// Internal parser +ptzMAP *_do_dmimap_parsing(xmlNode *node) { + ptzMAP *retmap = NULL; + xmlNode *ptr_n = NULL, *map_n = NULL;; + + // Go to the next XML_ELEMENT_NODE + for( map_n = node; map_n != NULL; map_n = map_n->next ) { + if( map_n->type == XML_ELEMENT_NODE ) { + break; + } + } + if( map_n == NULL ) { + return NULL; + } + + // Go to the first node + if( xmlStrcmp(node->name, (xmlChar *) "Map") != 0 ) { + map_n = dmixml_FindNode(node, "Map"); + if( map_n == NULL ) { + return NULL; + } + } + + // Loop through it's children + for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { + ptzTYPES type_key, type_value; + char *key = NULL, *value = NULL; + + if( ptr_n->type != XML_ELEMENT_NODE ) { + continue; + } + + // Get the attributes defining key, keytype, value and valuetype + key = dmixml_GetAttrValue(ptr_n, "key"); + type_key = _convert_maptype(dmixml_GetAttrValue(ptr_n, "keytype")); + + value = dmixml_GetAttrValue(ptr_n, "value"); + type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); + + if( type_value == ptzDICT ) { + // When value type is ptzDICT, traverse the children nodes + // - should contain another Map set instead of a value attribute + if( ptr_n->children == NULL ) { + continue; + } + // Recursion + retmap = ptzmap_Add(retmap, type_key, key, type_value, NULL, + _do_dmimap_parsing(ptr_n->children->next)); + } else { + // Append the value as a normal value when the + // value type is not a Python Dict + retmap = ptzmap_Add(retmap, type_key, key, type_value, value, NULL); + } + value = NULL; + key = NULL; + } + return retmap; +} + +// Main parser function for the mapping XML +ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { + ptzMAP *map = NULL; + xmlNode *node = NULL; + + // Find the root tag and locate our mapping + node = xmlDocGetRootElement(xmlmap); + assert( node != NULL ); + + // Verify that the root node got the right name + if( (node == NULL) + || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { + fprintf(stderr, "Invalid XML-Python mapping file\n"); + return NULL; + } + + // Verify that it's of a version we support + if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { + fprintf(stderr, "Unsupported XML-Python mapping file format\n"); + return NULL; + } + + // Find the section matching our request (mapname) + for( node = node->children->next; node != NULL; node = node->next ) { + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { + char *name = dmixml_GetAttrValue(node, "name"); + if( (name != NULL) && (strcmp(name, mapname) == 0) ) { + break; + } + } + } + + if( node == NULL ) { + fprintf(stderr, "No mapping for '%s' was found " + "in the XML-Python mapping file\n", mapname); + return NULL; + } + + // Start creating an internal map structure based on the mapping XML. + map = _do_dmimap_parsing(node); + + return map; +} + + +// +// Parser routines for converting XML data into Python structures +// + +inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { + PyObject *value; + + switch( type ) { + case ptzINT: + case ptzLIST_INT: + value = PyInt_FromLong((str != NULL ? atoi(str) : 0)); + break; + + case ptzFLOAT: + case ptzLIST_FLOAT: + value = PyFloat_FromDouble((str != NULL ? atof(str) : 0)); + break; + + case ptzSTR: + case ptzLIST_STR: + value = PyString_FromString(str); + break; + + default: + fprintf(stderr, "Invalid type '%i' for value '%s'\n", type, str); + value = Py_None; + } + return value; +} + + +// Retrieve a value from the XML doc (XPath Context) based on a XPath query +xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { + xmlChar *xp_xpr = NULL; + xmlXPathObject *xp_obj = NULL; + + if( xpath == NULL ) { + return NULL; + } + + xp_xpr = xmlCharStrdup(xpath); + xp_obj = xmlXPathEvalExpression(xp_xpr, xpctx); + assert( xp_obj != NULL ); + free(xp_xpr); + + if( (xp_obj->nodesetval == NULL) || (xp_obj->nodesetval->nodeNr == 0) ) { + xmlXPathFreeObject(xp_obj); + return NULL; + } + + return xp_obj; +} + +// Internal XML parser routine, which traverses the given mapping table, +// returning a Python structure accordingly to the map. +PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { + ptzMAP *map_p = NULL; + PyObject *retdata = NULL; + int i = 0; + + retdata = PyDict_New(); + for( map_p = in_map; map_p != NULL; map_p = map_p->next ) { + xmlXPathObject *xpobj = NULL; + char *key = NULL; + PyObject *value = NULL; + + // Get key value + switch( map_p->type_key ) { + case ptzCONST: + key = map_p->key; + break; + + case ptzSTR: + case ptzINT: + case ptzFLOAT: + xpobj = _get_xpath_values(xpctx, map_p->key); + if( xpobj != NULL ) { + key = dmixml_GetContent(xpobj->nodesetval->nodeTab[0]); + xmlXPathFreeObject(xpobj); + } + break; + default: + fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); + return Py_None; + break; + } + + // Get 'value' value + switch( map_p->type_value ) { + case ptzCONST: + value = PyString_FromString(map_p->value); + break; + + case ptzSTR: + case ptzINT: + case ptzFLOAT: + xpobj = _get_xpath_values(xpctx, map_p->value); + if( xpobj != NULL ) { + value = StringToPyObj(map_p->type_value, + dmixml_GetContent(xpobj->nodesetval->nodeTab[0])); + xmlXPathFreeObject(xpobj); + } + break; + + case ptzLIST_STR: + case ptzLIST_INT: + case ptzLIST_FLOAT: + xpobj = _get_xpath_values(xpctx, map_p->value); + value = PyList_New(0); + if( xpobj != NULL ) { + for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { + char *valstr = dmixml_GetContent(xpobj->nodesetval->nodeTab[i]); + PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); + } + xmlXPathFreeObject(xpobj); + } + break; + + case ptzDICT: + // Traverse the children to get the value of this element + value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); + Py_DECREF(value); + break; + + default: + fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); + free(key); key = NULL; + return Py_None; + break; + } + + PyDict_SetItemString(retdata, key, value); + Py_DECREF(value); + } + Py_INCREF(retdata); + return retdata; +} + +// Convert a xmlDoc to a Python object, based on the given map +PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *xmldoc) +{ + xmlXPathContext *xp_ctx = NULL; + PyObject *retdata = NULL; + + // Prepare a XPath context for XPath queries + xp_ctx = xmlXPathNewContext(xmldoc); + assert( xp_ctx != NULL ); + + // Parse the XML and create Python data + retdata = _do_pythonizeXML(map, xp_ctx, 0); + + // Clean up and return data + xmlXPathFreeContext(xp_ctx); + + return retdata; +} + +// Convert a xmlNode to a Python object, based on the given map +PyObject *pythonizeXMLnode(ptzMAP *map, xmlNode *nodes) +{ + xmlDoc *xmldoc = NULL; + PyObject *retdata = NULL; + + // Create our own internal XML doc and + // copy over the input nodes to our internal doc. + // This is needed as the XPath parser in libxml2 + // only works with xmlDoc. + xmldoc = xmlNewDoc((xmlChar *) "1.0"); + assert( xmldoc != NULL ); + xmlDocSetRootElement(xmldoc, xmlCopyNode(nodes, 1)); + + // Parse the internal xmlDoc + retdata = pythonizeXMLdoc(map, xmldoc); + + // Clean up and return data + xmlFreeDoc(xmldoc); + return retdata; +} + + + +#if 0 +// Simple independent main function - only for debugging +int main() { + xmlDoc *doc = NULL; + ptzMAP *map = NULL; + + doc = xmlReadFile("pythonmap.xml", NULL, 0); + assert( doc != NULL ); + + map = dmiMAP_ParseMappingXML(doc, "BIOSLanguage"); + ptzmap_Dump(map); + + ptzmap_Free(map); + xmlFreeDoc(doc); + + return 0; +} +#endif + +#if 0 +// Simple test module for Python - only for debugging +PyObject* demo_xmlpy() +{ + xmlDoc *doc = NULL, *mapping_xml = NULL; + ptzMAP *mapping = NULL; + PyObject *ret = NULL; + + // Read the XML-Python mapping setup + mapping_xml = xmlReadFile("pythonmap.xml", NULL, 0); + assert( mapping_xml != NULL ); + + mapping = dmiMAP_ParseMappingXML(mapping_xml, "BIOSLanguage"); + assert( mapping != NULL ); + + // Read XML data from file + doc = xmlReadFile("test.xml", NULL, 0); + assert( doc != NULL ); + + // Create a PyObject out of the XML indata + ret = pythonizeXMLdoc(mapping, doc); + + // Clean up and return the data + ptzmap_Free(mapping); + xmlFreeDoc(doc); + xmlFreeDoc(mapping_xml); + + return ret; +} + + +static PyMethodDef DemoMethods[] = { + {"xmlpy", demo_xmlpy, METH_NOARGS, ""}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initxmlpythonizer(void) { + PyObject *module = + Py_InitModule3((char *)"xmlpythonizer", DemoMethods, + "XML to Python Proof-of-Concept Python Module"); + + PyObject *version = PyString_FromString("2.10"); + Py_INCREF(version); + PyModule_AddObject(module, "version", version); +} +#endif // Python test module + -- cgit From 11691f4b5e5786878cca1d30b183103477d5311f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 28 Apr 2009 16:58:33 +0200 Subject: Updated xmlpythonizer to support boolean type and dynamic XPath keys * Added support boolean and list:boolean value types * Traversing child nodes and having dynamic keys Now it is possible to do the following: ** test.xml ** Option 1 Option 2 Option 3 ** mapping.xml ** Which should result in: {'Option 1': True, 'Option 2': False, 'Option 3': True'} --- src/xmlpythonizer.c | 121 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 35 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 92e0d7f..594717c 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -96,10 +96,10 @@ void ptzmap_Free_func(ptzMAP *ptr) } -#if 1 +#if 0 // DEBUG FUNCTIONS -static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", - "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", +static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", "ptzBOOL", + "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", "ptzLIST_BOOL", "ptzDICT", NULL }; void indent(int lvl) @@ -155,12 +155,16 @@ inline ptzTYPES _convert_maptype(const char *str) { return ptzINT; } else if( strcmp(str, "float") == 0 ) { return ptzFLOAT; + } else if( strcmp(str, "boolean") == 0 ) { + return ptzBOOL; } else if( strcmp(str, "list:string") == 0 ) { return ptzLIST_STR; } else if( strcmp(str, "list:integer") == 0 ) { return ptzLIST_INT; } else if( strcmp(str, "list:float") == 0 ) { return ptzLIST_FLOAT; + } else if( strcmp(str, "list:boolean") == 0 ) { + return ptzLIST_BOOL; } else if( strcmp(str, "dict") == 0 ) { return ptzDICT; } else { @@ -280,15 +284,24 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { PyObject *value; + if( str == NULL ) { + return Py_None; + } + switch( type ) { case ptzINT: case ptzLIST_INT: - value = PyInt_FromLong((str != NULL ? atoi(str) : 0)); + value = PyInt_FromLong(atoi(str)); break; case ptzFLOAT: case ptzLIST_FLOAT: - value = PyFloat_FromDouble((str != NULL ? atof(str) : 0)); + value = PyFloat_FromDouble(atof(str)); + break; + + case ptzBOOL: + case ptzLIST_BOOL: + value = PyBool_FromLong((atoi(str) == 1 ? 1:0)); break; case ptzSTR: @@ -326,6 +339,43 @@ xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { return xp_obj; } +inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { + char *key = NULL; + xmlXPathObject *xpobj = NULL; + + switch( map_p->type_key ) { + case ptzCONST: + key = map_p->key; + break; + + case ptzSTR: + case ptzINT: + case ptzFLOAT: + xpobj = _get_xpath_values(xpctx, map_p->key); + if( xpobj != NULL ) { + key = dmixml_GetContent(xpobj->nodesetval->nodeTab[idx]); + xmlXPathFreeObject(xpobj); + } + break; + + default: + fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); + break; + } + if( key == NULL ) { + fprintf(stderr, "Could not find the key value: %s\n", map_p->key); + } + return key; +} + + +#define PyADD_DICT_VALUE(p, k, v) { \ + if( k != NULL ) { \ + PyDict_SetItemString(p, k, v); \ + Py_DECREF(v); \ + } \ + } + // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { @@ -339,40 +389,27 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { char *key = NULL; PyObject *value = NULL; - // Get key value - switch( map_p->type_key ) { - case ptzCONST: - key = map_p->key; - break; - - case ptzSTR: - case ptzINT: - case ptzFLOAT: - xpobj = _get_xpath_values(xpctx, map_p->key); - if( xpobj != NULL ) { - key = dmixml_GetContent(xpobj->nodesetval->nodeTab[0]); - xmlXPathFreeObject(xpobj); - } - break; - default: - fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); - return Py_None; - break; - } - // Get 'value' value switch( map_p->type_value ) { case ptzCONST: value = PyString_FromString(map_p->value); + key = _get_key_value(map_p, xpctx, 0); + PyADD_DICT_VALUE(retdata, key, value); + break; case ptzSTR: case ptzINT: case ptzFLOAT: + case ptzBOOL: xpobj = _get_xpath_values(xpctx, map_p->value); if( xpobj != NULL ) { - value = StringToPyObj(map_p->type_value, - dmixml_GetContent(xpobj->nodesetval->nodeTab[0])); + for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { + value = StringToPyObj(map_p->type_value, + dmixml_GetContent(xpobj->nodesetval->nodeTab[i])); + key = _get_key_value(map_p, xpctx, i); + PyADD_DICT_VALUE(retdata, key, value); + } xmlXPathFreeObject(xpobj); } break; @@ -380,6 +417,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzLIST_STR: case ptzLIST_INT: case ptzLIST_FLOAT: + case ptzLIST_BOOL: xpobj = _get_xpath_values(xpctx, map_p->value); value = PyList_New(0); if( xpobj != NULL ) { @@ -388,6 +426,8 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); } xmlXPathFreeObject(xpobj); + key = _get_key_value(map_p, xpctx, 0); + PyADD_DICT_VALUE(retdata, key, value); } break; @@ -395,17 +435,16 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { // Traverse the children to get the value of this element value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); Py_DECREF(value); + + key = _get_key_value(map_p, xpctx, 0); + PyADD_DICT_VALUE(retdata, key, value); break; default: fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); - free(key); key = NULL; return Py_None; break; } - - PyDict_SetItemString(retdata, key, value); - Py_DECREF(value); } Py_INCREF(retdata); return retdata; @@ -457,16 +496,28 @@ PyObject *pythonizeXMLnode(ptzMAP *map, xmlNode *nodes) #if 0 // Simple independent main function - only for debugging int main() { - xmlDoc *doc = NULL; + xmlDoc *doc = NULL, *data = NULL; ptzMAP *map = NULL; + PyObject *pydat = NULL; doc = xmlReadFile("pythonmap.xml", NULL, 0); assert( doc != NULL ); - map = dmiMAP_ParseMappingXML(doc, "BIOSLanguage"); + map = dmiMAP_ParseMappingXML(doc, "bios"); ptzmap_Dump(map); + printf("----------------------\n"); + + + data = xmlReadFile("test.xml", NULL, 0); + assert( data != NULL ); + + pydat = pythonizeXMLdoc(map, data); + Py_INCREF(pydat); + PyObject_Print(pydat, stdout, 0); + Py_DECREF(pydat); ptzmap_Free(map); + xmlFreeDoc(data); xmlFreeDoc(doc); return 0; @@ -485,7 +536,7 @@ PyObject* demo_xmlpy() mapping_xml = xmlReadFile("pythonmap.xml", NULL, 0); assert( mapping_xml != NULL ); - mapping = dmiMAP_ParseMappingXML(mapping_xml, "BIOSLanguage"); + mapping = dmiMAP_ParseMappingXML(mapping_xml, "bios"); assert( mapping != NULL ); // Read XML data from file -- cgit From 4b925a1433b65c217e787804df3cf349d6b387aa Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 28 Apr 2009 19:10:45 +0200 Subject: Added filter and filtervalue attributes to xmlpythonizer's tags Using these attributes, only XML data (from the given XPath in 'filter') which matches the value in 'filtervalue' will be added to the Python data. --- src/xmlpythonizer.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 12 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 594717c..32f0181 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -40,6 +40,7 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, ptzTYPES ktyp, const char *key, ptzTYPES vtyp, const char *value, + const char *filter, const char *filterval, ptzMAP *child) { ptzMAP *ret = NULL; @@ -65,6 +66,11 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, ret->child = child; } + if( filter != NULL && filterval != NULL ) { + ret->filter = strdup(filter); + ret->filtervalue = strdup(filterval); + } + if( chain != NULL ) { ret->next = (ptzMAP *) chain; } @@ -86,6 +92,16 @@ void ptzmap_Free_func(ptzMAP *ptr) ptr->value = NULL; } + if( ptr->filter != NULL ) { + free(ptr->filter); + ptr->filter = NULL; + } + + if( ptr->filtervalue != NULL ) { + free(ptr->filtervalue); + ptr->filtervalue = NULL; + } + if( ptr->child != NULL ) { ptzmap_Free(ptr->child); } @@ -125,6 +141,10 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); indent(level); printf("value type: (%i) %-13.13s - value: %s\n", ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value); + if( ptr->filter != NULL ) { + indent(level); printf("filter: %s == %s\n", ptr->filter, ptr->filtervalue); + } + if( ptr->child != NULL ) { indent(level); printf(" ** CHILD\n"); ptzmap_Dump_func(ptr->child, level + 1); @@ -200,6 +220,7 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { ptzTYPES type_key, type_value; char *key = NULL, *value = NULL; + char *filter = NULL, *filterval = NULL; if( ptr_n->type != XML_ELEMENT_NODE ) { continue; @@ -212,6 +233,12 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { value = dmixml_GetAttrValue(ptr_n, "value"); type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); + // Get filters + filter = dmixml_GetAttrValue(ptr_n, "filter"); + if( filter != NULL ) { + filterval = dmixml_GetAttrValue(ptr_n, "filtervalue"); + } + if( type_value == ptzDICT ) { // When value type is ptzDICT, traverse the children nodes // - should contain another Map set instead of a value attribute @@ -219,12 +246,18 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { continue; } // Recursion - retmap = ptzmap_Add(retmap, type_key, key, type_value, NULL, + retmap = ptzmap_Add(retmap, type_key, key, + type_value, NULL, + filter, filterval, _do_dmimap_parsing(ptr_n->children->next)); + } else { // Append the value as a normal value when the // value type is not a Python Dict - retmap = ptzmap_Add(retmap, type_key, key, type_value, value, NULL); + retmap = ptzmap_Add(retmap, type_key, key, + type_value, value, + filter, filterval, + NULL); } value = NULL; key = NULL; @@ -272,7 +305,6 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // Start creating an internal map structure based on the mapping XML. map = _do_dmimap_parsing(node); - return map; } @@ -369,12 +401,42 @@ inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { } -#define PyADD_DICT_VALUE(p, k, v) { \ - if( k != NULL ) { \ - PyDict_SetItemString(p, k, v); \ - Py_DECREF(v); \ - } \ +void _register_value(PyObject *pyobj, xmlXPathContext *xpctx, + ptzMAP *map_p, const char *key, PyObject *value) +{ + if( key != NULL ) { + if( (map_p->filter != NULL) && (map_p->filtervalue != NULL) ) { + xmlXPathObject *xpobj = NULL; + int i = 0, found = 0; + + xpobj = _get_xpath_values(xpctx, map_p->filter); + if( (xpobj == NULL) || (xpobj->nodesetval->nodeNr < 1) ) { + // If node not found, or our value index is higher + // than what we found, filter it out. + if( xpobj != NULL ) { + xmlXPathFreeObject(xpobj); + } + return; + } + + for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { + if( strcmp(map_p->filtervalue, + dmixml_GetContent(xpobj->nodesetval->nodeTab[i])) == 0 ) { + found = 1; + break; + } + } + + if( found != 1 ) { + // If value did not match - no hit => do not add value + xmlXPathFreeObject(xpobj); + return; + } + } + PyDict_SetItemString(pyobj, key, value); + Py_DECREF(value); } +} // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. @@ -394,7 +456,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzCONST: value = PyString_FromString(map_p->value); key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); + _register_value(retdata, xpctx, map_p, key, value); break; @@ -408,7 +470,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { value = StringToPyObj(map_p->type_value, dmixml_GetContent(xpobj->nodesetval->nodeTab[i])); key = _get_key_value(map_p, xpctx, i); - PyADD_DICT_VALUE(retdata, key, value); + _register_value(retdata, xpctx, map_p, key, value); } xmlXPathFreeObject(xpobj); } @@ -427,7 +489,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { } xmlXPathFreeObject(xpobj); key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); + _register_value(retdata, xpctx, map_p, key, value); } break; @@ -437,7 +499,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { Py_DECREF(value); key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); + _register_value(retdata, xpctx, map_p, key, value); break; default: -- cgit From c6baf0a8f50cc19f319ad13ceeb2c40ace0b4d7e Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 29 Apr 2009 11:18:57 +0200 Subject: Exported ptzmap_Free() --- src/xmlpythonizer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 32f0181..91507e8 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -77,7 +77,6 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, return ret; }; -#define ptzmap_Free(ptr) { ptzmap_Free_func(ptr); ptr = NULL; } void ptzmap_Free_func(ptzMAP *ptr) { if( ptr == NULL ) { -- cgit From 7cf8017a95f04d6207ae3bbf923c8be5d873f6a1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 29 Apr 2009 13:07:16 +0200 Subject: Revert "Added filter and filtervalue attributes to xmlpythonizer's tags" This reverts commit 4b925a1433b65c217e787804df3cf349d6b387aa. Discovered that XPath got the needed power for filtering, no need for this extra feature --- src/xmlpythonizer.c | 86 ++++++++--------------------------------------------- 1 file changed, 12 insertions(+), 74 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 91507e8..fb8c8bb 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -40,7 +40,6 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, ptzTYPES ktyp, const char *key, ptzTYPES vtyp, const char *value, - const char *filter, const char *filterval, ptzMAP *child) { ptzMAP *ret = NULL; @@ -66,11 +65,6 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, ret->child = child; } - if( filter != NULL && filterval != NULL ) { - ret->filter = strdup(filter); - ret->filtervalue = strdup(filterval); - } - if( chain != NULL ) { ret->next = (ptzMAP *) chain; } @@ -91,16 +85,6 @@ void ptzmap_Free_func(ptzMAP *ptr) ptr->value = NULL; } - if( ptr->filter != NULL ) { - free(ptr->filter); - ptr->filter = NULL; - } - - if( ptr->filtervalue != NULL ) { - free(ptr->filtervalue); - ptr->filtervalue = NULL; - } - if( ptr->child != NULL ) { ptzmap_Free(ptr->child); } @@ -140,10 +124,6 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); indent(level); printf("value type: (%i) %-13.13s - value: %s\n", ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value); - if( ptr->filter != NULL ) { - indent(level); printf("filter: %s == %s\n", ptr->filter, ptr->filtervalue); - } - if( ptr->child != NULL ) { indent(level); printf(" ** CHILD\n"); ptzmap_Dump_func(ptr->child, level + 1); @@ -219,7 +199,6 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { ptzTYPES type_key, type_value; char *key = NULL, *value = NULL; - char *filter = NULL, *filterval = NULL; if( ptr_n->type != XML_ELEMENT_NODE ) { continue; @@ -232,12 +211,6 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { value = dmixml_GetAttrValue(ptr_n, "value"); type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); - // Get filters - filter = dmixml_GetAttrValue(ptr_n, "filter"); - if( filter != NULL ) { - filterval = dmixml_GetAttrValue(ptr_n, "filtervalue"); - } - if( type_value == ptzDICT ) { // When value type is ptzDICT, traverse the children nodes // - should contain another Map set instead of a value attribute @@ -245,18 +218,12 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { continue; } // Recursion - retmap = ptzmap_Add(retmap, type_key, key, - type_value, NULL, - filter, filterval, + retmap = ptzmap_Add(retmap, type_key, key, type_value, NULL, _do_dmimap_parsing(ptr_n->children->next)); - } else { // Append the value as a normal value when the // value type is not a Python Dict - retmap = ptzmap_Add(retmap, type_key, key, - type_value, value, - filter, filterval, - NULL); + retmap = ptzmap_Add(retmap, type_key, key, type_value, value, NULL); } value = NULL; key = NULL; @@ -304,6 +271,7 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // Start creating an internal map structure based on the mapping XML. map = _do_dmimap_parsing(node); + return map; } @@ -400,42 +368,12 @@ inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { } -void _register_value(PyObject *pyobj, xmlXPathContext *xpctx, - ptzMAP *map_p, const char *key, PyObject *value) -{ - if( key != NULL ) { - if( (map_p->filter != NULL) && (map_p->filtervalue != NULL) ) { - xmlXPathObject *xpobj = NULL; - int i = 0, found = 0; - - xpobj = _get_xpath_values(xpctx, map_p->filter); - if( (xpobj == NULL) || (xpobj->nodesetval->nodeNr < 1) ) { - // If node not found, or our value index is higher - // than what we found, filter it out. - if( xpobj != NULL ) { - xmlXPathFreeObject(xpobj); - } - return; - } - - for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { - if( strcmp(map_p->filtervalue, - dmixml_GetContent(xpobj->nodesetval->nodeTab[i])) == 0 ) { - found = 1; - break; - } - } - - if( found != 1 ) { - // If value did not match - no hit => do not add value - xmlXPathFreeObject(xpobj); - return; - } - } - PyDict_SetItemString(pyobj, key, value); - Py_DECREF(value); +#define PyADD_DICT_VALUE(p, k, v) { \ + if( k != NULL ) { \ + PyDict_SetItemString(p, k, v); \ + Py_DECREF(v); \ + } \ } -} // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. @@ -455,7 +393,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzCONST: value = PyString_FromString(map_p->value); key = _get_key_value(map_p, xpctx, 0); - _register_value(retdata, xpctx, map_p, key, value); + PyADD_DICT_VALUE(retdata, key, value); break; @@ -469,7 +407,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { value = StringToPyObj(map_p->type_value, dmixml_GetContent(xpobj->nodesetval->nodeTab[i])); key = _get_key_value(map_p, xpctx, i); - _register_value(retdata, xpctx, map_p, key, value); + PyADD_DICT_VALUE(retdata, key, value); } xmlXPathFreeObject(xpobj); } @@ -488,7 +426,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { } xmlXPathFreeObject(xpobj); key = _get_key_value(map_p, xpctx, 0); - _register_value(retdata, xpctx, map_p, key, value); + PyADD_DICT_VALUE(retdata, key, value); } break; @@ -498,7 +436,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { Py_DECREF(value); key = _get_key_value(map_p, xpctx, 0); - _register_value(retdata, xpctx, map_p, key, value); + PyADD_DICT_VALUE(retdata, key, value); break; default: -- cgit From 2aaa3c0822bff7204167f73b62035bc10f620881 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 29 Apr 2009 18:32:57 +0200 Subject: Reimplemented the XPath integration Now the XPath expressions can include XPath functions as well. The previous implementation only supported XPATH_NODESET results from XPath queries. Now XPATH_STRING and XPATH_NUMBER results are supported as well. XPATH_BOOLEAN might be needed later on. --- src/xmlpythonizer.c | 70 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 27 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index fb8c8bb..0b6c54e 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -330,11 +330,6 @@ xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { assert( xp_obj != NULL ); free(xp_xpr); - if( (xp_obj->nodesetval == NULL) || (xp_obj->nodesetval->nodeNr == 0) ) { - xmlXPathFreeObject(xp_obj); - return NULL; - } - return xp_obj; } @@ -351,8 +346,8 @@ inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { case ptzINT: case ptzFLOAT: xpobj = _get_xpath_values(xpctx, map_p->key); + key = dmixml_GetXPathContent(xpobj, idx); if( xpobj != NULL ) { - key = dmixml_GetContent(xpobj->nodesetval->nodeTab[idx]); xmlXPathFreeObject(xpobj); } break; @@ -361,20 +356,43 @@ inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); break; } - if( key == NULL ) { - fprintf(stderr, "Could not find the key value: %s\n", map_p->key); - } return key; } #define PyADD_DICT_VALUE(p, k, v) { \ - if( k != NULL ) { \ - PyDict_SetItemString(p, k, v); \ - Py_DECREF(v); \ - } \ + PyDict_SetItemString(p, k, v); \ + Py_DECREF(v); \ } +inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *map_p, xmlXPathObject *value) { + int i = 0; + char *key = NULL; + + assert( pydat != NULL && value != NULL ); + + switch( value->type ) { + case XPATH_NODESET: + for( i = 0; i < value->nodesetval->nodeNr; i++ ) { + key = _get_key_value(map_p, xpctx, i); + if( key != NULL ) { + char *val = NULL; + val = dmixml_GetXPathContent(value, i); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + } + } + break; + default: + key = _get_key_value(map_p, xpctx, 0); + if( key != NULL ) { + char *val = NULL; + val = dmixml_GetXPathContent(value, 0); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + } + break; + } +} + // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { @@ -391,10 +409,11 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { // Get 'value' value switch( map_p->type_value ) { case ptzCONST: - value = PyString_FromString(map_p->value); key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); - + if( key != NULL ) { + value = PyString_FromString(map_p->value); + PyADD_DICT_VALUE(retdata, key, value); + } break; case ptzSTR: @@ -403,12 +422,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzBOOL: xpobj = _get_xpath_values(xpctx, map_p->value); if( xpobj != NULL ) { - for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { - value = StringToPyObj(map_p->type_value, - dmixml_GetContent(xpobj->nodesetval->nodeTab[i])); - key = _get_key_value(map_p, xpctx, i); - PyADD_DICT_VALUE(retdata, key, value); - } + _add_xpath_result(retdata, xpctx, map_p, xpobj); xmlXPathFreeObject(xpobj); } break; @@ -421,8 +435,9 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { value = PyList_New(0); if( xpobj != NULL ) { for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { - char *valstr = dmixml_GetContent(xpobj->nodesetval->nodeTab[i]); + char *valstr = dmixml_GetXPathContent(xpobj, i); PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); + free(valstr); } xmlXPathFreeObject(xpobj); key = _get_key_value(map_p, xpctx, 0); @@ -432,11 +447,12 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzDICT: // Traverse the children to get the value of this element - value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); - Py_DECREF(value); - key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); + if( key != NULL ) { + value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); + Py_DECREF(value); + PyADD_DICT_VALUE(retdata, key, value); + } break; default: -- cgit From cea1270777d0a5bd42284011307fe183a67f8ada Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 30 Apr 2009 16:07:43 +0200 Subject: Rewritten dmixml_GetXPathContent(...) and _get_key_value(...) This rewrite was to handle XPATH_NUMBER more correctly. Now these functions needs an preallocated memory buffer for the result. --- src/xmlpythonizer.c | 69 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 26 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 0b6c54e..6287ea2 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -333,29 +333,36 @@ xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { return xp_obj; } -inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { - char *key = NULL; +char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { xmlXPathObject *xpobj = NULL; + memset(key, 0, buflen); + switch( map_p->type_key ) { case ptzCONST: - key = map_p->key; + strncpy(key, map_p->key, buflen-1); break; case ptzSTR: case ptzINT: case ptzFLOAT: xpobj = _get_xpath_values(xpctx, map_p->key); - key = dmixml_GetXPathContent(xpobj, idx); - if( xpobj != NULL ) { + if( xpobj == NULL ) { + return NULL; + } + if( dmixml_GetXPathContent(key, buflen, xpobj, idx) == NULL ) { xmlXPathFreeObject(xpobj); + return NULL; } + xmlXPathFreeObject(xpobj); break; default: fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); - break; + return NULL; } + // We consider to have a key, if the first byte is a readable + // character (usually starting at 0x20/32d) return key; } @@ -368,29 +375,34 @@ inline char *_get_key_value(ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *map_p, xmlXPathObject *value) { int i = 0; char *key = NULL; + char *val = NULL; assert( pydat != NULL && value != NULL ); + key = (char *) malloc(258); + assert( key != NULL ); + + val = (char *) malloc(4098); + assert( val != NULL ); + switch( value->type ) { case XPATH_NODESET: for( i = 0; i < value->nodesetval->nodeNr; i++ ) { - key = _get_key_value(map_p, xpctx, i); - if( key != NULL ) { - char *val = NULL; - val = dmixml_GetXPathContent(value, i); + if( _get_key_value(key, 256, map_p, xpctx, i) != NULL ) { + dmixml_GetXPathContent(val, 4097, value, i); PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); } } break; default: - key = _get_key_value(map_p, xpctx, 0); - if( key != NULL ) { - char *val = NULL; - val = dmixml_GetXPathContent(value, 0); + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + dmixml_GetXPathContent(val, 4097, value, 0); PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); } break; } + free(key); + free(val); } // Internal XML parser routine, which traverses the given mapping table, @@ -399,18 +411,20 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { ptzMAP *map_p = NULL; PyObject *retdata = NULL; int i = 0; + char *key = NULL; + + key = (char *) malloc(258); + assert( key != NULL ); retdata = PyDict_New(); for( map_p = in_map; map_p != NULL; map_p = map_p->next ) { xmlXPathObject *xpobj = NULL; - char *key = NULL; PyObject *value = NULL; // Get 'value' value switch( map_p->type_value ) { case ptzCONST: - key = _get_key_value(map_p, xpctx, 0); - if( key != NULL ) { + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { value = PyString_FromString(map_p->value); PyADD_DICT_VALUE(retdata, key, value); } @@ -434,21 +448,23 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { xpobj = _get_xpath_values(xpctx, map_p->value); value = PyList_New(0); if( xpobj != NULL ) { - for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { - char *valstr = dmixml_GetXPathContent(xpobj, i); - PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); - free(valstr); + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { + char *valstr = NULL; + valstr = (char *) malloc(4098); + dmixml_GetXPathContent(valstr, 4097, xpobj, i); + PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); + free(valstr); + } + xmlXPathFreeObject(xpobj); + PyADD_DICT_VALUE(retdata, key, value); } - xmlXPathFreeObject(xpobj); - key = _get_key_value(map_p, xpctx, 0); - PyADD_DICT_VALUE(retdata, key, value); } break; case ptzDICT: // Traverse the children to get the value of this element - key = _get_key_value(map_p, xpctx, 0); - if( key != NULL ) { + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); Py_DECREF(value); PyADD_DICT_VALUE(retdata, key, value); @@ -461,6 +477,7 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { break; } } + free(key); Py_INCREF(retdata); return retdata; } -- cgit From 1ccdf74b1e537c4bd747c079530a5d9ea904e138 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 4 May 2009 10:39:02 +0200 Subject: Improved error handling when parsing mapping XML --- src/xmlpythonizer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 6287ea2..3c00f6b 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -243,13 +243,13 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // Verify that the root node got the right name if( (node == NULL) || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { - fprintf(stderr, "Invalid XML-Python mapping file\n"); + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); return NULL; } // Verify that it's of a version we support if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - fprintf(stderr, "Unsupported XML-Python mapping file format\n"); + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); return NULL; } @@ -264,8 +264,10 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { } if( node == NULL ) { - fprintf(stderr, "No mapping for '%s' was found " - "in the XML-Python mapping file\n", mapname); + char msg[8194]; + snprintf(msg, 8193, "No mapping for '%s' was found " + "in the XML-Python mapping file%c", mapname, 0); + PyErr_SetString(PyExc_IOError, msg); return NULL; } -- cgit From 94e81cb43908f90ccdeca4d7d459172999d4ae90 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 13 May 2009 17:39:33 +0200 Subject: Big rewrite of xmlpythonizer - Supports relative XPaths now by using the rootpath attribute in the Map tag. This path is then set for all elements inside this Map tag. - Rewrote the parser to recurse correctly. The former version did not recurse well on the very outer (first) Map level. --- src/xmlpythonizer.c | 231 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 155 insertions(+), 76 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 3c00f6b..0065633 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -37,7 +37,7 @@ #include "dmixml.h" #include "xmlpythonizer.h" -ptzMAP *ptzmap_Add(const ptzMAP *chain, +ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, ptzTYPES ktyp, const char *key, ptzTYPES vtyp, const char *value, ptzMAP *child) @@ -53,6 +53,10 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, assert( ret != NULL ); memset(ret, 0, sizeof(ptzMAP)+2); + if( rootp != NULL ) { + ret->rootpath = strdup(rootp); + } + ret->type_key = ktyp; ret->key = strdup(key); @@ -77,6 +81,11 @@ void ptzmap_Free_func(ptzMAP *ptr) return; } + if( ptr->rootpath != NULL ) { + free(ptr->rootpath); + ptr->rootpath = NULL; + } + free(ptr->key); ptr->key = NULL; @@ -199,6 +208,7 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { ptzTYPES type_key, type_value; char *key = NULL, *value = NULL; + char *rootpath = NULL; if( ptr_n->type != XML_ELEMENT_NODE ) { continue; @@ -211,6 +221,8 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { value = dmixml_GetAttrValue(ptr_n, "value"); type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); + rootpath = dmixml_GetAttrValue(ptr_n, "rootpath"); + if( type_value == ptzDICT ) { // When value type is ptzDICT, traverse the children nodes // - should contain another Map set instead of a value attribute @@ -218,12 +230,12 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { continue; } // Recursion - retmap = ptzmap_Add(retmap, type_key, key, type_value, NULL, + retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, NULL, _do_dmimap_parsing(ptr_n->children->next)); } else { // Append the value as a normal value when the // value type is not a Python Dict - retmap = ptzmap_Add(retmap, type_key, key, type_value, value, NULL); + retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, value, NULL); } value = NULL; key = NULL; @@ -243,13 +255,13 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // Verify that the root node got the right name if( (node == NULL) || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + // PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); return NULL; } // Verify that it's of a version we support if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + // PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); return NULL; } @@ -267,7 +279,7 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { char msg[8194]; snprintf(msg, 8193, "No mapping for '%s' was found " "in the XML-Python mapping file%c", mapname, 0); - PyErr_SetString(PyExc_IOError, msg); + // PyErr_SetString(PyExc_IOError, msg); return NULL; } @@ -281,7 +293,6 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // // Parser routines for converting XML data into Python structures // - inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { PyObject *value; @@ -317,7 +328,6 @@ inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { return value; } - // Retrieve a value from the XML doc (XPath Context) based on a XPath query xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { xmlChar *xp_xpr = NULL; @@ -365,10 +375,11 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x } // We consider to have a key, if the first byte is a readable // character (usually starting at 0x20/32d) - return key; + return ((key != NULL) && (strlen(key) > 0) ? key : NULL) ; } + #define PyADD_DICT_VALUE(p, k, v) { \ PyDict_SetItemString(p, k, v); \ Py_DECREF(v); \ @@ -389,10 +400,19 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m switch( value->type ) { case XPATH_NODESET: - for( i = 0; i < value->nodesetval->nodeNr; i++ ) { - if( _get_key_value(key, 256, map_p, xpctx, i) != NULL ) { - dmixml_GetXPathContent(val, 4097, value, i); - PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + if( value->nodesetval == NULL ) { + break; + } + if( value->nodesetval->nodeNr == 0 ) { + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + PyADD_DICT_VALUE(pydat, key, Py_None); + } + } else { + for( i = 0; i < value->nodesetval->nodeNr; i++ ) { + if( _get_key_value(key, 256, map_p, xpctx, i) != NULL ) { + dmixml_GetXPathContent(val, 4097, value, i); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + } } } break; @@ -407,28 +427,43 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m free(val); } + // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. -PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { +PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *in_map, xmlNode *data_n, int elmtid) { ptzMAP *map_p = NULL; - PyObject *retdata = NULL; - int i = 0; char *key = NULL; + xmlXPathContext *xpctx = NULL; + xmlDoc *xpdoc = NULL; + + xpdoc = xmlNewDoc((xmlChar *) "1.0"); + assert( xpdoc != NULL ); + xmlDocSetRootElement(xpdoc, xmlCopyNode(data_n, 1)); + + xpctx = xmlXPathNewContext(xpdoc); + assert( xpctx != NULL ); + xpctx->node = data_n; key = (char *) malloc(258); assert( key != NULL ); - retdata = PyDict_New(); - for( map_p = in_map; map_p != NULL; map_p = map_p->next ) { - xmlXPathObject *xpobj = NULL; + for( map_p = in_map; map_p != NULL; map_p = map_p->next) { + xmlXPathObject *xpo = NULL; PyObject *value = NULL; + int i; - // Get 'value' value + // Extract value switch( map_p->type_value ) { case ptzCONST: if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { value = PyString_FromString(map_p->value); PyADD_DICT_VALUE(retdata, key, value); + } else { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + map_p->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + continue; } break; @@ -436,10 +471,10 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzINT: case ptzFLOAT: case ptzBOOL: - xpobj = _get_xpath_values(xpctx, map_p->value); - if( xpobj != NULL ) { - _add_xpath_result(retdata, xpctx, map_p, xpobj); - xmlXPathFreeObject(xpobj); + xpo = _get_xpath_values(xpctx, map_p->value); + if( xpo != NULL ) { + _add_xpath_result(retdata, xpctx, map_p, xpo); + xmlXPathFreeObject(xpo); } break; @@ -447,86 +482,128 @@ PyObject *_do_pythonizeXML(ptzMAP *in_map, xmlXPathContext *xpctx, int lvl) { case ptzLIST_INT: case ptzLIST_FLOAT: case ptzLIST_BOOL: - xpobj = _get_xpath_values(xpctx, map_p->value); - value = PyList_New(0); - if( xpobj != NULL ) { + xpo = _get_xpath_values(xpctx, map_p->value); + if( xpo != NULL ) { if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - for( i = 0; i < xpobj->nodesetval->nodeNr; i++ ) { - char *valstr = NULL; - valstr = (char *) malloc(4098); - dmixml_GetXPathContent(valstr, 4097, xpobj, i); - PyList_Append(value, StringToPyObj(map_p->type_value, valstr)); - free(valstr); + if( xpo->nodesetval->nodeNr > 0 ) { + value = PyList_New(0); + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + char *valstr = NULL; + valstr = (char *) malloc(4098); + dmixml_GetXPathContent(valstr, 4097, xpo, i); + PyList_Append(value, StringToPyObj(map_p->type_value, + valstr)); + free(valstr); + } + } else { + value = Py_None; } - xmlXPathFreeObject(xpobj); PyADD_DICT_VALUE(retdata, key, value); + xmlXPathFreeObject(xpo); + } else { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: " + "%s [%i] (Defining key: %s)%c", + map_p->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + continue; } } break; case ptzDICT: - // Traverse the children to get the value of this element - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - value = _do_pythonizeXML(map_p->child, xpctx, lvl+1); - Py_DECREF(value); - PyADD_DICT_VALUE(retdata, key, value); + // Traverse children nodes + if( map_p->child == NULL ) { + break; + } + if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + in_map->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + continue; } + value = pythonizeXMLnode(map_p->child, data_n); + PyADD_DICT_VALUE(retdata, key, (value != NULL ? value : Py_None)); break; default: fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); - return Py_None; break; } } + free(key); - Py_INCREF(retdata); + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); return retdata; } -// Convert a xmlDoc to a Python object, based on the given map -PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *xmldoc) -{ - xmlXPathContext *xp_ctx = NULL; +// Convert a xmlNode to a Python object, based on the given map +PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { + xmlXPathContext *xpctx = NULL; + xmlDoc *xpdoc = NULL; PyObject *retdata = NULL; - // Prepare a XPath context for XPath queries - xp_ctx = xmlXPathNewContext(xmldoc); - assert( xp_ctx != NULL ); + if( (in_map == NULL) || (data_n == NULL) ) { + PyErr_SetString(PyExc_LookupError, "XMLnode or map is NULL"); + return NULL; + } - // Parse the XML and create Python data - retdata = _do_pythonizeXML(map, xp_ctx, 0); + // Set the root node in the XPath context + retdata = PyDict_New(); + if( in_map->rootpath != NULL ) { + xmlXPathObject *xpo = NULL; + int i; + + xpdoc = xmlNewDoc((xmlChar *) "1.0"); + assert( xpdoc != NULL ); + xmlDocSetRootElement(xpdoc, xmlCopyNode(data_n, 1)); + + xpctx = xmlXPathNewContext(xpdoc); + assert( xpctx != NULL ); + xpctx->node = data_n; + + xpo = _get_xpath_values(xpctx, in_map->rootpath); + if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { + char msg[8094]; + snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", + in_map->rootpath, in_map->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + + if( xpo != NULL ) { + xmlXPathFreeObject(xpo); + } + xmlFreeDoc(xpdoc); + xmlXPathFreeContext(xpctx); + return NULL; + } - // Clean up and return data - xmlXPathFreeContext(xp_ctx); + retdata = PyDict_New(); + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + _deep_pythonize(retdata, in_map, xpo->nodesetval->nodeTab[i], i); + } + xmlXPathFreeObject(xpo); + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + } else { + _deep_pythonize(retdata, in_map, data_n, 0); + } return retdata; } -// Convert a xmlNode to a Python object, based on the given map -PyObject *pythonizeXMLnode(ptzMAP *map, xmlNode *nodes) -{ - xmlDoc *xmldoc = NULL; - PyObject *retdata = NULL; - // Create our own internal XML doc and - // copy over the input nodes to our internal doc. - // This is needed as the XPath parser in libxml2 - // only works with xmlDoc. - xmldoc = xmlNewDoc((xmlChar *) "1.0"); - assert( xmldoc != NULL ); - xmlDocSetRootElement(xmldoc, xmlCopyNode(nodes, 1)); - - // Parse the internal xmlDoc - retdata = pythonizeXMLdoc(map, xmldoc); +// Convert a xmlDoc to a Python object, based on the given map +PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) +{ + xmlNode *node = NULL; - // Clean up and return data - xmlFreeDoc(xmldoc); - return retdata; + node = xmlDocGetRootElement(doc); + return pythonizeXMLnode(map, node); } - #if 0 // Simple independent main function - only for debugging int main() { @@ -534,15 +611,17 @@ int main() { ptzMAP *map = NULL; PyObject *pydat = NULL; + Py_Initialize(); + doc = xmlReadFile("pythonmap.xml", NULL, 0); assert( doc != NULL ); - map = dmiMAP_ParseMappingXML(doc, "bios"); - ptzmap_Dump(map); + map = dmiMAP_ParseMappingXML(doc, "processor"); + // ptzmap_Dump(map); printf("----------------------\n"); - data = xmlReadFile("test.xml", NULL, 0); + data = xmlReadFile("cpu.xml", NULL, 0); assert( data != NULL ); pydat = pythonizeXMLdoc(map, data); @@ -574,7 +653,7 @@ PyObject* demo_xmlpy() assert( mapping != NULL ); // Read XML data from file - doc = xmlReadFile("test.xml", NULL, 0); + doc = xmlReadFile("cpu.xml", NULL, 0); assert( doc != NULL ); // Create a PyObject out of the XML indata @@ -588,7 +667,6 @@ PyObject* demo_xmlpy() return ret; } - static PyMethodDef DemoMethods[] = { {"xmlpy", demo_xmlpy, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} @@ -605,3 +683,4 @@ PyMODINIT_FUNC initxmlpythonizer(void) { } #endif // Python test module + -- cgit From eeb40ea2c5a47737f318a1631316416e6f1ab75a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 14 May 2009 14:57:12 +0200 Subject: Fixed another parser issue When using rootpath, it did not parse all elements as expected. Also restricted the rootpath to only work when valuetype="dict". --- src/xmlpythonizer.c | 233 +++++++++++++++++++++++++++------------------------- 1 file changed, 122 insertions(+), 111 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 0065633..f033e6d 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -129,6 +129,9 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) return; } + if( ptr->rootpath != NULL ) { + indent(level); printf("root path: %s\n", ptr->rootpath); + } indent(level); printf("key type: (%i) %-13.13s - key: %s\n", ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); indent(level); printf("value type: (%i) %-13.13s - value: %s\n", @@ -430,11 +433,13 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m // Internal XML parser routine, which traverses the given mapping table, // returning a Python structure accordingly to the map. -PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *in_map, xmlNode *data_n, int elmtid) { - ptzMAP *map_p = NULL; +PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int elmtid) { char *key = NULL; xmlXPathContext *xpctx = NULL; xmlDoc *xpdoc = NULL; + xmlXPathObject *xpo = NULL; + PyObject *value = NULL; + int i; xpdoc = xmlNewDoc((xmlChar *) "1.0"); assert( xpdoc != NULL ); @@ -447,90 +452,83 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *in_map, xmlNode *data_n, in key = (char *) malloc(258); assert( key != NULL ); - for( map_p = in_map; map_p != NULL; map_p = map_p->next) { - xmlXPathObject *xpo = NULL; - PyObject *value = NULL; - int i; + // Extract value + switch( map_p->type_value ) { + case ptzCONST: + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + value = PyString_FromString(map_p->value); + PyADD_DICT_VALUE(retdata, key, value); + } else { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + map_p->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + } + break; + + case ptzSTR: + case ptzINT: + case ptzFLOAT: + case ptzBOOL: + xpo = _get_xpath_values(xpctx, map_p->value); + if( xpo != NULL ) { + _add_xpath_result(retdata, xpctx, map_p, xpo); + xmlXPathFreeObject(xpo); + } + break; - // Extract value - switch( map_p->type_value ) { - case ptzCONST: + case ptzLIST_STR: + case ptzLIST_INT: + case ptzLIST_FLOAT: + case ptzLIST_BOOL: + xpo = _get_xpath_values(xpctx, map_p->value); + if( xpo != NULL ) { if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - value = PyString_FromString(map_p->value); + if( xpo->nodesetval->nodeNr > 0 ) { + value = PyList_New(0); + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + char *valstr = NULL; + valstr = (char *) malloc(4098); + dmixml_GetXPathContent(valstr, 4097, xpo, i); + PyList_Append(value, StringToPyObj(map_p->type_value, + valstr)); + free(valstr); + } + } else { + value = Py_None; + } PyADD_DICT_VALUE(retdata, key, value); + xmlXPathFreeObject(xpo); } else { char msg[8094]; - snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + snprintf(msg, 8092, "Could not get key value: " + "%s [%i] (Defining key: %s)%c", map_p->rootpath, elmtid, map_p->key, 0); PyErr_SetString(PyExc_LookupError, msg); - continue; - } - break; - - case ptzSTR: - case ptzINT: - case ptzFLOAT: - case ptzBOOL: - xpo = _get_xpath_values(xpctx, map_p->value); - if( xpo != NULL ) { - _add_xpath_result(retdata, xpctx, map_p, xpo); - xmlXPathFreeObject(xpo); } - break; - - case ptzLIST_STR: - case ptzLIST_INT: - case ptzLIST_FLOAT: - case ptzLIST_BOOL: - xpo = _get_xpath_values(xpctx, map_p->value); - if( xpo != NULL ) { - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - if( xpo->nodesetval->nodeNr > 0 ) { - value = PyList_New(0); - for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { - char *valstr = NULL; - valstr = (char *) malloc(4098); - dmixml_GetXPathContent(valstr, 4097, xpo, i); - PyList_Append(value, StringToPyObj(map_p->type_value, - valstr)); - free(valstr); - } - } else { - value = Py_None; - } - PyADD_DICT_VALUE(retdata, key, value); - xmlXPathFreeObject(xpo); - } else { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: " - "%s [%i] (Defining key: %s)%c", - map_p->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - continue; - } - } - break; + } + break; - case ptzDICT: - // Traverse children nodes - if( map_p->child == NULL ) { - break; - } - if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", - in_map->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - continue; - } - value = pythonizeXMLnode(map_p->child, data_n); - PyADD_DICT_VALUE(retdata, key, (value != NULL ? value : Py_None)); + case ptzDICT: + // Traverse children nodes + if( map_p->child == NULL ) { break; - - default: - fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); + } + if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + map_p->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); break; } + // Use recursion when procession child elements + value = pythonizeXMLnode(map_p->child, data_n); + PyADD_DICT_VALUE(retdata, key, (value != NULL ? value : Py_None)); + break; + + default: + fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); + break; } free(key); @@ -544,52 +542,65 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xmlXPathContext *xpctx = NULL; xmlDoc *xpdoc = NULL; PyObject *retdata = NULL; + ptzMAP *map_p = NULL; + char *key = NULL; if( (in_map == NULL) || (data_n == NULL) ) { PyErr_SetString(PyExc_LookupError, "XMLnode or map is NULL"); return NULL; } - // Set the root node in the XPath context - retdata = PyDict_New(); - if( in_map->rootpath != NULL ) { - xmlXPathObject *xpo = NULL; - int i; + key = (char *) malloc(258); + assert( key != NULL ); - xpdoc = xmlNewDoc((xmlChar *) "1.0"); - assert( xpdoc != NULL ); - xmlDocSetRootElement(xpdoc, xmlCopyNode(data_n, 1)); + // Loop through all configured elements + retdata = PyDict_New(); + for( map_p = in_map; map_p != NULL; map_p = map_p->next ) { + if( (map_p->type_value == ptzDICT) && (map_p->rootpath != NULL) ) { + xmlXPathObject *xpo = NULL; + int i; + + // Set the root node in the XPath context + xpdoc = xmlNewDoc((xmlChar *) "1.0"); + assert( xpdoc != NULL ); + xmlDocSetRootElement(xpdoc, xmlCopyNode(data_n, 1)); + + xpctx = xmlXPathNewContext(xpdoc); + assert( xpctx != NULL ); + xpctx->node = data_n; + + xpo = _get_xpath_values(xpctx, map_p->rootpath); + if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { + char msg[8094]; + snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", + map_p->rootpath, map_p->key, 0); + fprintf(stderr, msg); + PyErr_SetString(PyExc_LookupError, msg); - xpctx = xmlXPathNewContext(xpdoc); - assert( xpctx != NULL ); - xpctx->node = data_n; + if( xpo != NULL ) { + xmlXPathFreeObject(xpo); + } + xmlFreeDoc(xpdoc); + xmlXPathFreeContext(xpctx); + return NULL; + } - xpo = _get_xpath_values(xpctx, in_map->rootpath); - if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { - char msg[8094]; - snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", - in_map->rootpath, in_map->key, 0); - PyErr_SetString(PyExc_LookupError, msg); + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + xpctx->node = xpo->nodesetval->nodeTab[i]; - if( xpo != NULL ) { - xmlXPathFreeObject(xpo); + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + _deep_pythonize(retdata, map_p, + xpo->nodesetval->nodeTab[i], i); + } } - xmlFreeDoc(xpdoc); + xmlXPathFreeObject(xpo); xmlXPathFreeContext(xpctx); - return NULL; - } - - retdata = PyDict_New(); - for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { - _deep_pythonize(retdata, in_map, xpo->nodesetval->nodeTab[i], i); + xmlFreeDoc(xpdoc); + } else { + _deep_pythonize(retdata, map_p, data_n, 0); } - xmlXPathFreeObject(xpo); - xmlXPathFreeContext(xpctx); - xmlFreeDoc(xpdoc); - } else { - _deep_pythonize(retdata, in_map, data_n, 0); } - + free(key); return retdata; } @@ -606,7 +617,7 @@ PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) #if 0 // Simple independent main function - only for debugging -int main() { +int main(int argc, char **argv) { xmlDoc *doc = NULL, *data = NULL; ptzMAP *map = NULL; PyObject *pydat = NULL; @@ -616,19 +627,19 @@ int main() { doc = xmlReadFile("pythonmap.xml", NULL, 0); assert( doc != NULL ); - map = dmiMAP_ParseMappingXML(doc, "processor"); - // ptzmap_Dump(map); + map = dmiMAP_ParseMappingXML(doc, argv[1]); + ptzmap_Dump(map); printf("----------------------\n"); - data = xmlReadFile("cpu.xml", NULL, 0); + data = xmlReadFile(argv[2], NULL, 0); assert( data != NULL ); pydat = pythonizeXMLdoc(map, data); Py_INCREF(pydat); PyObject_Print(pydat, stdout, 0); Py_DECREF(pydat); - + printf("\n"); ptzmap_Free(map); xmlFreeDoc(data); xmlFreeDoc(doc); -- cgit From a92cc1236ca7c5abee27e4360284b67297e39c15 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 14 May 2009 16:31:34 +0200 Subject: Support fixed size lists When using one of the list types as valuetype, the Map tag now also supports fixedsize and index_attr attributes. - fixedsize : Defines a fixed size of the list - index_attr : Defines an attribute name of the input XML data which contains the list index for the value --- src/xmlpythonizer.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 3 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index f033e6d..e9671b2 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -75,6 +75,23 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, return ret; }; +void ptzmap_SetFixedList(ptzMAP *map_p, const char *index, int size) { + assert( map_p != NULL ); + + switch( map_p->type_value ) { + case ptzLIST_STR: + case ptzLIST_INT: + case ptzLIST_FLOAT: + case ptzLIST_BOOL: + map_p->list_index = strdup(index); + map_p->fixed_list_size = size; + break; + + default: + break; + } +} + void ptzmap_Free_func(ptzMAP *ptr) { if( ptr == NULL ) { @@ -86,6 +103,11 @@ void ptzmap_Free_func(ptzMAP *ptr) ptr->rootpath = NULL; } + if( ptr->list_index != NULL ) { + free(ptr->list_index); + ptr->list_index = NULL; + } + free(ptr->key); ptr->key = NULL; @@ -136,6 +158,11 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); indent(level); printf("value type: (%i) %-13.13s - value: %s\n", ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value); + if( ptr->list_index != NULL ) { + indent(level); + printf("List index: %s - Fixed size: %i\n", + ptr->list_index, ptr->fixed_list_size); + } if( ptr->child != NULL ) { indent(level); printf(" ** CHILD\n"); ptzmap_Dump_func(ptr->child, level + 1); @@ -212,7 +239,8 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { ptzTYPES type_key, type_value; char *key = NULL, *value = NULL; char *rootpath = NULL; - + char *listidx = NULL; + int fixedsize = 0; if( ptr_n->type != XML_ELEMENT_NODE ) { continue; } @@ -226,6 +254,12 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { rootpath = dmixml_GetAttrValue(ptr_n, "rootpath"); + listidx = dmixml_GetAttrValue(ptr_n, "index_attr"); + if( listidx != NULL ) { + char *fsz = dmixml_GetAttrValue(ptr_n, "fixedsize"); + fixedsize = (fsz != NULL ? atoi(fsz) : 0); + } + if( type_value == ptzDICT ) { // When value type is ptzDICT, traverse the children nodes // - should contain another Map set instead of a value attribute @@ -240,6 +274,11 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { // value type is not a Python Dict retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, value, NULL); } + + if( (retmap != NULL) && (listidx != NULL) && (fixedsize > 0) ) { + ptzmap_SetFixedList(retmap, listidx, fixedsize); + } + value = NULL; key = NULL; } @@ -486,12 +525,37 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { if( xpo->nodesetval->nodeNr > 0 ) { value = PyList_New(0); + + // If we're working on a fixed list, create one which contains + // only Py_None objects. Otherwise the list will be filled with + // elements. + if( map_p->fixed_list_size > 0 ) { + for( i = 0; i < map_p->fixed_list_size; i++ ) { + PyList_Append(value, Py_None); + } + } + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { char *valstr = NULL; valstr = (char *) malloc(4098); dmixml_GetXPathContent(valstr, 4097, xpo, i); - PyList_Append(value, StringToPyObj(map_p->type_value, - valstr)); + + // If we have a fixed list and we have a index value for the list + if( (map_p->fixed_list_size > 0) && (map_p->list_index != NULL) ) { + char *idx = NULL; + + idx = dmixml_GetAttrValue(xpo->nodesetval->nodeTab[i], + map_p->list_index); + if( idx != NULL ) { + PyList_SetItem(value, atoi(idx)-1, + StringToPyObj(map_p->type_value, + valstr) + ); + } + } else { + PyList_Append(value, StringToPyObj(map_p->type_value, + valstr)); + } free(valstr); } } else { -- cgit From 9d47720a88ee77ac4c0ab5f138a8eaf601c492d0 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 14 May 2009 17:06:18 +0200 Subject: Added new Map attribute - emptyIsNone If the emptyIsNone attribute is set to "1", the Python result will be forced to Py_None if the referenced XML value is empty. When checking if the value is empty, the XML value is right trimmed to remove trailing spaces. Only spaces are are removed. --- src/xmlpythonizer.c | 71 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index e9671b2..b8964bf 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -156,8 +156,9 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) } indent(level); printf("key type: (%i) %-13.13s - key: %s\n", ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); - indent(level); printf("value type: (%i) %-13.13s - value: %s\n", - ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value); + indent(level); printf("value type: (%i) %-13.13s - value: %s %s\n", + ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value, + (ptr->num_emptyIsNone ? "(EmptyIsNone)": "")); if( ptr->list_index != NULL ) { indent(level); printf("List index: %s - Fixed size: %i\n", @@ -270,9 +271,29 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, NULL, _do_dmimap_parsing(ptr_n->children->next)); } else { + char *emptyIsNone = NULL; + // Append the value as a normal value when the // value type is not a Python Dict retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, value, NULL); + + // Set emptyIsNone flag + if( (emptyIsNone = dmixml_GetAttrValue(ptr_n, "emptyIsNone")) != NULL ) { + switch( retmap->type_value ) { + case ptzSTR: + case ptzINT: + case ptzFLOAT: + case ptzBOOL: + case ptzLIST_STR: + case ptzLIST_INT: + case ptzLIST_FLOAT: + case ptzLIST_BOOL: + retmap->emptyIsNone = (emptyIsNone[0] == '1' ? 1 : 0); + break; + default: + break; + } + } } if( (retmap != NULL) && (listidx != NULL) && (fixedsize > 0) ) { @@ -297,13 +318,13 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // Verify that the root node got the right name if( (node == NULL) || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { - // PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); return NULL; } // Verify that it's of a version we support if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - // PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); return NULL; } @@ -321,7 +342,7 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { char msg[8194]; snprintf(msg, 8193, "No mapping for '%s' was found " "in the XML-Python mapping file%c", mapname, 0); - // PyErr_SetString(PyExc_IOError, msg); + PyErr_SetString(PyExc_IOError, msg); return NULL; } @@ -335,14 +356,38 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // // Parser routines for converting XML data into Python structures // -inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { +inline PyObject *StringToPyObj(ptzMAP *val_m, const char *str) { PyObject *value; if( str == NULL ) { return Py_None; } - switch( type ) { + if( val_m->emptyIsNone == 1) { + char *cp = strdup(str); + char *cp_p = NULL; + assert( cp != NULL ); + + // Trim the string for trailing spaces + cp_p = cp + strlen(cp) - 1; + while( (cp_p >= cp) && (*cp_p == ' ') ) { + *cp_p = 0; + cp_p--; + } + + // If our copy pointer is the same + // or less than the starting point, + // there is no data here + if( cp_p <= cp ) { + free(cp); + return Py_None; + } + free(cp); + } + + + + switch( val_m->type_value ) { case ptzINT: case ptzLIST_INT: value = PyInt_FromLong(atoi(str)); @@ -364,7 +409,7 @@ inline PyObject *StringToPyObj(ptzTYPES type, const char *str) { break; default: - fprintf(stderr, "Invalid type '%i' for value '%s'\n", type, str); + fprintf(stderr, "Invalid type '%i' for value '%s'\n", val_m->type_value, str); value = Py_None; } return value; @@ -453,7 +498,7 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m for( i = 0; i < value->nodesetval->nodeNr; i++ ) { if( _get_key_value(key, 256, map_p, xpctx, i) != NULL ) { dmixml_GetXPathContent(val, 4097, value, i); - PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p, val)); } } } @@ -461,7 +506,7 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m default: if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { dmixml_GetXPathContent(val, 4097, value, 0); - PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p->type_value, val)); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p, val)); } break; } @@ -548,13 +593,11 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int map_p->list_index); if( idx != NULL ) { PyList_SetItem(value, atoi(idx)-1, - StringToPyObj(map_p->type_value, - valstr) + StringToPyObj(map_p, valstr) ); } } else { - PyList_Append(value, StringToPyObj(map_p->type_value, - valstr)); + PyList_Append(value, StringToPyObj(map_p, valstr)); } free(valstr); } -- cgit From 72016cb607798e567ac2f2ce67cc50652b0daa32 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 15 May 2009 11:06:20 +0200 Subject: Added 'emptyValue' attribute in the Map tag This attribute defines a default value when XML source data is empty --- src/xmlpythonizer.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index b8964bf..4690981 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -108,6 +108,11 @@ void ptzmap_Free_func(ptzMAP *ptr) ptr->list_index = NULL; } + if( ptr->emptyValue != NULL ) { + free(ptr->emptyValue); + ptr->emptyValue = NULL; + } + free(ptr->key); ptr->key = NULL; @@ -271,14 +276,14 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, NULL, _do_dmimap_parsing(ptr_n->children->next)); } else { - char *emptyIsNone = NULL; + char *tmpstr = NULL; // Append the value as a normal value when the // value type is not a Python Dict retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, value, NULL); // Set emptyIsNone flag - if( (emptyIsNone = dmixml_GetAttrValue(ptr_n, "emptyIsNone")) != NULL ) { + if( (tmpstr = dmixml_GetAttrValue(ptr_n, "emptyIsNone")) != NULL ) { switch( retmap->type_value ) { case ptzSTR: case ptzINT: @@ -288,12 +293,15 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { case ptzLIST_INT: case ptzLIST_FLOAT: case ptzLIST_BOOL: - retmap->emptyIsNone = (emptyIsNone[0] == '1' ? 1 : 0); + retmap->emptyIsNone = (tmpstr[0] == '1' ? 1 : 0); break; default: break; } } + if( (tmpstr = dmixml_GetAttrValue(ptr_n, "emptyValue")) != NULL ) { + retmap->emptyValue = strdup(tmpstr); + } } if( (retmap != NULL) && (listidx != NULL) && (fixedsize > 0) ) { @@ -356,15 +364,16 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { // // Parser routines for converting XML data into Python structures // -inline PyObject *StringToPyObj(ptzMAP *val_m, const char *str) { +inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { PyObject *value; + const char *workstr = NULL; - if( str == NULL ) { + if( instr == NULL ) { return Py_None; } - if( val_m->emptyIsNone == 1) { - char *cp = strdup(str); + if( (val_m->emptyIsNone == 1) || (val_m->emptyValue != NULL) ) { + char *cp = strdup(instr); char *cp_p = NULL; assert( cp != NULL ); @@ -380,36 +389,45 @@ inline PyObject *StringToPyObj(ptzMAP *val_m, const char *str) { // there is no data here if( cp_p <= cp ) { free(cp); - return Py_None; + if( val_m->emptyIsNone == 1 ) { + return Py_None; + } + if( val_m->emptyValue != NULL ) { + workstr = (const char *)val_m->emptyValue; + } + } else { + free(cp); } - free(cp); } + if( workstr == NULL ) { + workstr = instr; + } switch( val_m->type_value ) { case ptzINT: case ptzLIST_INT: - value = PyInt_FromLong(atoi(str)); + value = PyInt_FromLong(atoi(workstr)); break; case ptzFLOAT: case ptzLIST_FLOAT: - value = PyFloat_FromDouble(atof(str)); + value = PyFloat_FromDouble(atof(workstr)); break; case ptzBOOL: case ptzLIST_BOOL: - value = PyBool_FromLong((atoi(str) == 1 ? 1:0)); + value = PyBool_FromLong((atoi(workstr) == 1 ? 1:0)); break; case ptzSTR: case ptzLIST_STR: - value = PyString_FromString(str); + value = PyString_FromString(workstr); break; default: - fprintf(stderr, "Invalid type '%i' for value '%s'\n", val_m->type_value, str); + fprintf(stderr, "Invalid type '%i' for value '%s'\n", val_m->type_value, instr); value = Py_None; } return value; -- cgit From 599642f7370cb3f2fbf5c079c20269318d5a775f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 19 May 2009 15:29:56 +0200 Subject: Added support for value type 'list:dict' for field mapping This builds up a list of dicts. Syntax is: The parser will iterate all nodes defined in the @value attribute and the root path will of the nested mapping will be using the path in @value as the root path for further parsing. --- src/xmlpythonizer.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 12 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 4690981..d9827bd 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -46,8 +46,6 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, assert( (ktyp == ptzCONST) || (ktyp == ptzSTR) || (ktyp == ptzINT) || (ktyp == ptzFLOAT) ); assert( key != NULL ); - // Make sure that value and child are not used together - assert( ((value == NULL) && child != NULL) || ((value != NULL) && (child == NULL)) ); ret = (ptzMAP *) malloc(sizeof(ptzMAP)+2); assert( ret != NULL ); @@ -63,9 +61,9 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, ret->type_value = vtyp; if( value != NULL ) { ret->value = strdup(value); - ret->child = NULL; - } else if( child != NULL ) { - ret->value = NULL; + } + + if( child != NULL ) { ret->child = child; } @@ -135,7 +133,7 @@ void ptzmap_Free_func(ptzMAP *ptr) // DEBUG FUNCTIONS static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", "ptzBOOL", "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", "ptzLIST_BOOL", - "ptzDICT", NULL }; + "ptzDICT", "ptzLIST_DICT", NULL }; void indent(int lvl) { @@ -163,7 +161,7 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) ptr->type_key, ptzTYPESstr[ptr->type_key], ptr->key); indent(level); printf("value type: (%i) %-13.13s - value: %s %s\n", ptr->type_value, ptzTYPESstr[ptr->type_value], ptr->value, - (ptr->num_emptyIsNone ? "(EmptyIsNone)": "")); + (ptr->emptyIsNone ? "(EmptyIsNone)": "")); if( ptr->list_index != NULL ) { indent(level); printf("List index: %s - Fixed size: %i\n", @@ -211,9 +209,11 @@ inline ptzTYPES _convert_maptype(const char *str) { return ptzLIST_BOOL; } else if( strcmp(str, "dict") == 0 ) { return ptzDICT; + } else if( strcmp(str, "list:dict") == 0 ) { + return ptzLIST_DICT; } else { - fprintf(stderr, "Unknown field type: %s - defaulting to 'string'\n", str); - return ptzSTR; + fprintf(stderr, "Unknown field type: %s - defaulting to 'constant'\n", str); + return ptzCONST; } } @@ -266,14 +266,15 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { fixedsize = (fsz != NULL ? atoi(fsz) : 0); } - if( type_value == ptzDICT ) { + if( (type_value == ptzDICT) || (type_value == ptzLIST_DICT) ) { // When value type is ptzDICT, traverse the children nodes // - should contain another Map set instead of a value attribute if( ptr_n->children == NULL ) { continue; } // Recursion - retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, NULL, + retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, + (type_value == ptzLIST_DICT ? value : NULL), _do_dmimap_parsing(ptr_n->children->next)); } else { char *tmpstr = NULL; @@ -615,6 +616,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int ); } } else { + // No list index - append the value PyList_Append(value, StringToPyObj(map_p, valstr)); } free(valstr); @@ -651,6 +653,69 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int PyADD_DICT_VALUE(retdata, key, (value != NULL ? value : Py_None)); break; + case ptzLIST_DICT: // List of dict arrays + if( map_p->child == NULL ) { + break; + } + if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { + char msg[8094]; + snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", + map_p->rootpath, elmtid, map_p->key, 0); + PyErr_SetString(PyExc_LookupError, msg); + break; + } + + // Iterate all nodes which is found in the 'value' XPath + xpo = _get_xpath_values(xpctx, map_p->value); + if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { + char msg[8094]; + snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", + map_p->value, map_p->key, 0); + fprintf(stderr, msg); + PyErr_SetString(PyExc_LookupError, msg); + + if( xpo != NULL ) { + xmlXPathFreeObject(xpo); + } + break; + } + + // Prepare a data list + value = PyList_New(0); + + // If we're working on a fixed list, create one which contains + // only Py_None objects. Otherwise the list will be filled with + // elements. + if( map_p->fixed_list_size > 0 ) { + for( i = 0; i < map_p->fixed_list_size; i++ ) { + PyList_Append(value, Py_None); + } + } + + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + PyObject *dataset = NULL; + + dataset = pythonizeXMLnode(map_p->child, xpo->nodesetval->nodeTab[i]); + if( dataset != NULL ) { + // If we have a fixed list and we have a index value for the list + if( (map_p->fixed_list_size > 0) && (map_p->list_index != NULL) ) { + char *idx = NULL; + + idx = dmixml_GetAttrValue(xpo->nodesetval->nodeTab[i], + map_p->list_index); + if( idx != NULL ) { + PyList_SetItem(value, atoi(idx)-1, dataset); + } + } else { + // No list index - append the value + PyList_Append(value, dataset); + } + } + } + PyADD_DICT_VALUE(retdata, key, value); + xmlXPathFreeObject(xpo); + break; + default: fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); break; @@ -762,9 +827,10 @@ int main(int argc, char **argv) { pydat = pythonizeXMLdoc(map, data); Py_INCREF(pydat); + printf("\n\n"); PyObject_Print(pydat, stdout, 0); Py_DECREF(pydat); - printf("\n"); + printf("\n\n"); ptzmap_Free(map); xmlFreeDoc(data); xmlFreeDoc(doc); -- cgit From d06d776adb0fef9504bd7662760e4cd0971fb748 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Fri, 22 May 2009 23:49:55 +1000 Subject: Reversioned, relicensed, and rejigged The version is of now, v3.10.6. The version major field has been upped due to the newly added XML functionality. The version has been reverted to GPLv2. Some headers have been cleaned up, copyright notices added etc. Credits given where due. --- src/xmlpythonizer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index d9827bd..d987802 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -1,3 +1,4 @@ + /* Converts XML docs and nodes to Python dicts and lists by * using an XML file which describes the Python dict layout * -- cgit From a18a72fab2a622077d5257003b09be30ab283339 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sat, 23 May 2009 14:37:01 +1000 Subject: More cleanup Don't write to stdout unless in debug mode (with respect to writing to memory devices. Added the xml datafile to setup (distutils). Updated test case (incorporating color and cleaning up tests). --- src/xmlpythonizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index d987802..dceeaa2 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -880,7 +880,7 @@ PyMODINIT_FUNC initxmlpythonizer(void) { Py_InitModule3((char *)"xmlpythonizer", DemoMethods, "XML to Python Proof-of-Concept Python Module"); - PyObject *version = PyString_FromString("2.10"); + PyObject *version = PyString_FromString("3.10.6"); Py_INCREF(version); PyModule_AddObject(module, "version", version); } -- cgit From f17fca75b0766caeba992bd62ab9c87cc6a79acc Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sat, 23 May 2009 15:21:42 +1000 Subject: Completed test case Removed trailing spaces from xml data file. Commented out fprintf()s for now (Perhapse should add them to the debug build at least). --- src/xmlpythonizer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index dceeaa2..f1d755e 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -672,7 +672,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int char msg[8094]; snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", map_p->value, map_p->key, 0); - fprintf(stderr, msg); + //fprintf(stderr, msg); PyErr_SetString(PyExc_LookupError, msg); if( xpo != NULL ) { @@ -765,7 +765,7 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { char msg[8094]; snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", map_p->rootpath, map_p->key, 0); - fprintf(stderr, msg); + //fprintf(stderr, msg); PyErr_SetString(PyExc_LookupError, msg); if( xpo != NULL ) { -- cgit From 6b1598c8b98699b115525155b43d19365e79dd08 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sat, 23 May 2009 23:02:46 +1000 Subject: Reimplementing the type() function - WIP --- src/xmlpythonizer.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index f1d755e..ea78b94 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -35,6 +35,7 @@ #include #include +#include "util.h" #include "dmixml.h" #include "xmlpythonizer.h" @@ -338,14 +339,22 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { return NULL; } - // Find the section matching our request (mapname) - for( node = node->children->next; node != NULL; node = node->next ) { - if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { - char *name = dmixml_GetAttrValue(node, "name"); - if( (name != NULL) && (strcmp(name, mapname) == 0) ) { - break; + if(!is_int(mapname)) { + // Find the section matching our request (mapname) + for( node = node->children->next; node != NULL; node = node->next ) { + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { + char *name = dmixml_GetAttrValue(node, "name"); + if( (name != NULL) && (strcmp(name, mapname) == 0) ) { + break; + } } } + } else { + //. FIXME + char msg[8194]; + snprintf(msg, 8193, "Not (yet) implemented%c", 0); + PyErr_SetString(PyExc_SystemError, msg); + return NULL; } if( node == NULL ) { -- cgit From af27ba4dd2ffdef8e4ee3abf187475c1b3303f71 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sun, 24 May 2009 00:26:23 +1000 Subject: Completed preliminary reimplementation of type() Updated test unit to match. Throw an exception instead of returning None/False in some functions. --- src/xmlpythonizer.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index ea78b94..836e4da 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -339,22 +339,29 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { return NULL; } - if(!is_int(mapname)) { - // Find the section matching our request (mapname) - for( node = node->children->next; node != NULL; node = node->next ) { - if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { - char *name = dmixml_GetAttrValue(node, "name"); - if( (name != NULL) && (strcmp(name, mapname) == 0) ) { - break; - } + int type_id = is_int(mapname); + if(type_id > -1) { + //FIXME + char *python_xml_typemap = strdup(PYTHON_XML_TYPEMAP); + xmlDoc *typemappingxml = xmlReadFile(python_xml_typemap, NULL, 0); + xmlNode *node = xmlDocGetRootElement(typemappingxml); + xmlNode *wally; + char type_id_hex[5]; + snprintf(type_id_hex, 5, "0x%02x", type_id); + wally = dmixml_FindNodeByAttr(node, "id", type_id_hex); + if(wally) { + mapname = dmixml_GetAttrValue(wally, "value"); + } + } + + // Find the section matching our request (mapname) + for( node = node->children->next; node != NULL; node = node->next ) { + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { + char *name = dmixml_GetAttrValue(node, "name"); + if( (name != NULL) && (strcmp(name, mapname) == 0) ) { + break; } } - } else { - //. FIXME - char msg[8194]; - snprintf(msg, 8193, "Not (yet) implemented%c", 0); - PyErr_SetString(PyExc_SystemError, msg); - return NULL; } if( node == NULL ) { -- cgit From 6b21c755269a80f3988259157d47430f491448be Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sun, 24 May 2009 02:17:21 +1000 Subject: Broken commit - change in XML mapping design Rather than hardcoding the data by function name (e.g. system, bios, connector, slot, etc), create each `type' as an individual XML tree, then group them under user-friendly names (as per the function names). Here the `pythonmap.xml' groups (but does not define) the various types (0..255), the types themselves are however defined in `typemap.xml'. This commit is broken, and a WIP. --- src/xmlpythonizer.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 836e4da..11766b0 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -256,6 +256,7 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { // Get the attributes defining key, keytype, value and valuetype key = dmixml_GetAttrValue(ptr_n, "key"); type_key = _convert_maptype(dmixml_GetAttrValue(ptr_n, "keytype")); +fprintf(stderr, "%s\n", key); value = dmixml_GetAttrValue(ptr_n, "value"); type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); @@ -352,14 +353,22 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { if(wally) { mapname = dmixml_GetAttrValue(wally, "value"); } - } - - // Find the section matching our request (mapname) - for( node = node->children->next; node != NULL; node = node->next ) { - if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { - char *name = dmixml_GetAttrValue(node, "name"); - if( (name != NULL) && (strcmp(name, mapname) == 0) ) { - break; + for( node = node->children->next; node != NULL; node = node->next ) { + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { + char *name = dmixml_GetAttrValue(node, "name"); + if( (name != NULL) && (strcmp(name, mapname) == 0) ) { + break; + } + } + } + } else { + // Find the section matching our request (mapname) + for( node = node->children->next; node != NULL; node = node->next ) { + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { + char *name = dmixml_GetAttrValue(node, "name"); + if( (name != NULL) && (strcmp(name, mapname) == 0) ) { + break; + } } } } -- cgit From e5a38d8131071d302a1cce0cace50f14f7f643b5 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sun, 24 May 2009 03:47:49 +1000 Subject: Autoheadered --- src/xmlpythonizer.c | 155 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 42 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 11766b0..3099e5d 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -1,9 +1,44 @@ +/*. ******* coding:utf-8 AUTOHEADER START v1.1 ******* + *. vim: fileencoding=utf-8 syntax=c sw=8 ts=8 et + *. + *. © 2009 David Sommerseth + *. © 2007-2009 Nima Talebi + *. + *. This file is part of Python DMI-Decode. + *. + *. Python DMI-Decode is free software: you can redistribute it and/or modify + *. it under the terms of the GNU General Public License as published by + *. the Free Software Foundation, either version 2 of the License, or + *. (at your option) any later version. + *. + *. Python DMI-Decode is distributed in the hope that it will be useful, + *. but WITHOUT ANY WARRANTY; without even the implied warranty of + *. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + *. GNU General Public License for more details. + *. + *. You should have received a copy of the GNU General Public License + *. along with Python DMI-Decode. If not, see . + *. + *. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + *. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + *. EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + *. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + *. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + *. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + *. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + *. OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + *. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *. + *. ADAPTED M. STONE & T. PARKER DISCLAIMER: THIS SOFTWARE COULD RESULT IN INJURY + *. AND/OR DEATH, AND AS SUCH, IT SHOULD NOT BE BUILT, INSTALLED OR USED BY ANYONE. + *. + *. $AutoHeaderSerial::20090522 $ + *. ******* AUTOHEADER END v1.1 ******* */ /* Converts XML docs and nodes to Python dicts and lists by * using an XML file which describes the Python dict layout * - * Copyright 2009 David Sommerseth - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -219,8 +254,8 @@ inline ptzTYPES _convert_maptype(const char *str) { } } -// Internal parser -ptzMAP *_do_dmimap_parsing(xmlNode *node) { +// Internal parser - SubMapper (Individual Types of a Group) +ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL;; @@ -256,7 +291,6 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node) { // Get the attributes defining key, keytype, value and valuetype key = dmixml_GetAttrValue(ptr_n, "key"); type_key = _convert_maptype(dmixml_GetAttrValue(ptr_n, "keytype")); -fprintf(stderr, "%s\n", key); value = dmixml_GetAttrValue(ptr_n, "value"); type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); @@ -278,7 +312,7 @@ fprintf(stderr, "%s\n", key); // Recursion retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, (type_value == ptzLIST_DICT ? value : NULL), - _do_dmimap_parsing(ptr_n->children->next)); + _do_dmitypemap_parsing(ptr_n->children->next)); } else { char *tmpstr = NULL; @@ -318,50 +352,89 @@ fprintf(stderr, "%s\n", key); return retmap; } -// Main parser function for the mapping XML -ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { - ptzMAP *map = NULL; - xmlNode *node = NULL; - - // Find the root tag and locate our mapping - node = xmlDocGetRootElement(xmlmap); - assert( node != NULL ); +// Internal parser - Mapper (Groups of Types) +ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap, xmlDoc *xmltypemap) { + ptzMAP *retmap = NULL; + xmlNode *ptr_n = NULL, *map_n = NULL;; - // Verify that the root node got the right name - if( (node == NULL) - || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + // Go to the next XML_ELEMENT_NODE + for( map_n = node; map_n != NULL; map_n = map_n->next ) { + if( map_n->type == XML_ELEMENT_NODE ) { + break; + } + } + if( map_n == NULL ) { return NULL; } - // Verify that it's of a version we support - if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); - return NULL; + // Go to the first node + if( xmlStrcmp(node->name, (xmlChar *) "TypeMap") != 0 ) { + map_n = dmixml_FindNode(node, "TypeMap"); + if( map_n == NULL ) { + return NULL; + } } + // Loop through it's children + xmlNode *typemap = xmlDocGetRootElement(xmltypemap); + assert( typemap != NULL ); + for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { + char *type_id = NULL; + type_id = dmixml_GetAttrValue(ptr_n, "id"); + map_n = dmixml_FindNodeByAttr(typemap, "id", type_id); + retmap = _do_dmitypemap_parsing(map_n); + break; + } + return retmap; +} + + + +// Main parser function for the mapping XML +ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, xmlDoc *xmltypemap, const char *mapname) { + ptzMAP *map = NULL; + xmlNode *node = NULL; + int type_id = is_int(mapname); if(type_id > -1) { - //FIXME - char *python_xml_typemap = strdup(PYTHON_XML_TYPEMAP); - xmlDoc *typemappingxml = xmlReadFile(python_xml_typemap, NULL, 0); - xmlNode *node = xmlDocGetRootElement(typemappingxml); - xmlNode *wally; + // Find the root tag and locate our mapping + node = xmlDocGetRootElement(xmltypemap); + assert( node != NULL ); + + // Verify that the root node got the right name + if( (node == NULL) + || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_typemap") != 0 )) { + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + return NULL; + } + + // Verify that it's of a version we support + if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + return NULL; + } + char type_id_hex[5]; snprintf(type_id_hex, 5, "0x%02x", type_id); - wally = dmixml_FindNodeByAttr(node, "id", type_id_hex); - if(wally) { - mapname = dmixml_GetAttrValue(wally, "value"); + node = dmixml_FindNodeByAttr(node, "id", type_id_hex); + } else { + // Find the root tag and locate our mapping + node = xmlDocGetRootElement(xmlmap); + assert( node != NULL ); + + // Verify that the root node got the right name + if( (node == NULL) + || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + return NULL; } - for( node = node->children->next; node != NULL; node = node->next ) { - if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { - char *name = dmixml_GetAttrValue(node, "name"); - if( (name != NULL) && (strcmp(name, mapname) == 0) ) { - break; - } - } + + // Verify that it's of a version we support + if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + return NULL; } - } else { + // Find the section matching our request (mapname) for( node = node->children->next; node != NULL; node = node->next ) { if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { @@ -382,7 +455,7 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { } // Start creating an internal map structure based on the mapping XML. - map = _do_dmimap_parsing(node); + map = (type_id == -1) ? _do_dmimap_parsing(node, xmlmap, xmltypemap) : _do_dmitypemap_parsing(node); return map; } @@ -697,7 +770,6 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int char msg[8094]; snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", map_p->value, map_p->key, 0); - //fprintf(stderr, msg); PyErr_SetString(PyExc_LookupError, msg); if( xpo != NULL ) { @@ -787,10 +859,9 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xpo = _get_xpath_values(xpctx, map_p->rootpath); if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { - char msg[8094]; + char msg[8094]; //XXX snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", map_p->rootpath, map_p->key, 0); - //fprintf(stderr, msg); PyErr_SetString(PyExc_LookupError, msg); if( xpo != NULL ) { -- cgit From 13ff9d7e48ab1574b36473f75701cc7f7c1e461a Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Wed, 27 May 2009 00:11:54 +1000 Subject: WIP commit Merged the two XML files into one, and amended relevant code. I still want to modify the XML tag names, but not yet. The calls to dmidecode.type() not function as expected, but the others are broken - this is next. --- src/xmlpythonizer.c | 70 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 3099e5d..86bbb69 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -353,8 +353,9 @@ ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { } // Internal parser - Mapper (Groups of Types) -ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap, xmlDoc *xmltypemap) { +ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap) { ptzMAP *retmap = NULL; + ptzMAP *tmp = NULL; xmlNode *ptr_n = NULL, *map_n = NULL;; // Go to the next XML_ELEMENT_NODE @@ -376,14 +377,21 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap, xmlDoc *xmltypemap) { } // Loop through it's children - xmlNode *typemap = xmlDocGetRootElement(xmltypemap); + xmlNode *typemap = xmlDocGetRootElement(xmlmap); assert( typemap != NULL ); + for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { char *type_id = NULL; + type_id = dmixml_GetAttrValue(ptr_n, "id"); map_n = dmixml_FindNodeByAttr(typemap, "id", type_id); - retmap = _do_dmitypemap_parsing(map_n); - break; + if( tmp != NULL) { + tmp->next = _do_dmitypemap_parsing(map_n); + tmp = tmp->next; + } else { + tmp = _do_dmitypemap_parsing(map_n); + retmap = tmp; + } } return retmap; } @@ -391,50 +399,40 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap, xmlDoc *xmltypemap) { // Main parser function for the mapping XML -ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, xmlDoc *xmltypemap, const char *mapname) { +ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { ptzMAP *map = NULL; xmlNode *node = NULL; int type_id = is_int(mapname); - if(type_id > -1) { - // Find the root tag and locate our mapping - node = xmlDocGetRootElement(xmltypemap); - assert( node != NULL ); - // Verify that the root node got the right name - if( (node == NULL) - || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_typemap") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); - return NULL; - } + // Find the root tag and locate our mapping + node = xmlDocGetRootElement(xmlmap); + assert( node != NULL ); - // Verify that it's of a version we support - if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); - return NULL; - } + // Verify that the root node got the right name + if( (node == NULL) + || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_mapping") != 0 )) { + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + return NULL; + } + + // Verify that it's of a version we support + if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + return NULL; + } + + if(type_id > -1) { + node = dmixml_FindNode(node, "TypeMapping"); + assert( node != NULL ); char type_id_hex[5]; snprintf(type_id_hex, 5, "0x%02x", type_id); node = dmixml_FindNodeByAttr(node, "id", type_id_hex); } else { - // Find the root tag and locate our mapping - node = xmlDocGetRootElement(xmlmap); + node = dmixml_FindNode(node, "GroupMapping"); assert( node != NULL ); - // Verify that the root node got the right name - if( (node == NULL) - || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_fieldmap") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); - return NULL; - } - - // Verify that it's of a version we support - if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); - return NULL; - } - // Find the section matching our request (mapname) for( node = node->children->next; node != NULL; node = node->next ) { if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { @@ -455,7 +453,7 @@ ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, xmlDoc *xmltypemap, const char *m } // Start creating an internal map structure based on the mapping XML. - map = (type_id == -1) ? _do_dmimap_parsing(node, xmlmap, xmltypemap) : _do_dmitypemap_parsing(node); + map = (type_id == -1) ? _do_dmimap_parsing(node, xmlmap) : _do_dmitypemap_parsing(node); return map; } -- cgit From 81f781c18d59fa5ec822136f9469fd5b6881ca2a Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Wed, 27 May 2009 12:33:51 +1000 Subject: Fixed WIP from last night (with notes) Note that this will not work as expected for `group mappings' that have unimplemented `type maps', and this is because the linked-list chain will ne broken at the first unimplemented `type map' There is no reason to code a workaround for this as the type do have to be implemented eventually, and hence added code will merely be noise. --- src/xmlpythonizer.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 86bbb69..34f6947 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -349,6 +349,7 @@ ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { value = NULL; key = NULL; } + return retmap; } @@ -377,20 +378,23 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap) { } // Loop through it's children - xmlNode *typemap = xmlDocGetRootElement(xmlmap); + xmlNode *typemap = dmixml_FindNode(xmlDocGetRootElement(xmlmap), "TypeMapping"); assert( typemap != NULL ); + char *type_id; for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { - char *type_id = NULL; - + //. TODO: Dazo: I had to add this (if() statement), but not sure why I should need to + //. TODO: Needs investigation... type_id = dmixml_GetAttrValue(ptr_n, "id"); - map_n = dmixml_FindNodeByAttr(typemap, "id", type_id); - if( tmp != NULL) { - tmp->next = _do_dmitypemap_parsing(map_n); - tmp = tmp->next; - } else { - tmp = _do_dmitypemap_parsing(map_n); - retmap = tmp; + if(type_id) { + map_n = dmixml_FindNodeByAttr(typemap, "id", type_id); + if( tmp != NULL) { + tmp->next = _do_dmitypemap_parsing(map_n); + tmp = tmp->next; + } else { + retmap = _do_dmitypemap_parsing(map_n); + tmp = retmap; + } } } return retmap; @@ -766,7 +770,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int xpo = _get_xpath_values(xpctx, map_p->value); if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { char msg[8094]; - snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", + snprintf(msg, 8092, "Could not locate XML path node (e1): %s (Defining key: %s)%c", map_p->value, map_p->key, 0); PyErr_SetString(PyExc_LookupError, msg); @@ -858,7 +862,7 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xpo = _get_xpath_values(xpctx, map_p->rootpath); if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { char msg[8094]; //XXX - snprintf(msg, 8092, "Could not locate XML path node: %s (Defining key: %s)%c", + snprintf(msg, 8092, "Could not locate XML path node (e2): %s (Defining key: %s)%c", map_p->rootpath, map_p->key, 0); PyErr_SetString(PyExc_LookupError, msg); -- cgit From 3149fdcec94191102fd801c7967a5e3cb5b330a7 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 2 Jun 2009 15:40:57 +0200 Subject: Rewrote the dmiMAP_ParseMappingXML(...) function and split it up Removed the automagic in the dmiMAP_ParseMappingXML(...) function from automatically decide what to parse (TypeMapping or GroupMapping). Introduced two new functions instead: - dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *name) Parses the XML mapping document, using the GroupMapping tags and building up a proper ptzMAP structure for all TypeMap defined in that group. - dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *typeid) Parses the XML mapping document, using only the TypeMapping section in th mapping document. Rewrote a lot of internal parts to reuse as much of the existing code as possible. --- src/xmlpythonizer.c | 199 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 77 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 34f6947..f1ecee7 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -74,6 +74,14 @@ #include "dmixml.h" #include "xmlpythonizer.h" + +ptzMAP *ptzmap_AppendMap(const ptzMAP *chain, ptzMAP *newmap) { + if( chain != NULL ) { + newmap->next = (ptzMAP *) chain; + } + return newmap; +} + ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, ptzTYPES ktyp, const char *key, ptzTYPES vtyp, const char *value, @@ -104,10 +112,7 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, ret->child = child; } - if( chain != NULL ) { - ret->next = (ptzMAP *) chain; - } - return ret; + return ptzmap_AppendMap(chain, ret); }; void ptzmap_SetFixedList(ptzMAP *map_p, const char *index, int size) { @@ -166,7 +171,7 @@ void ptzmap_Free_func(ptzMAP *ptr) } -#if 0 +#if 1 // DEBUG FUNCTIONS static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", "ptzBOOL", "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", "ptzLIST_BOOL", @@ -255,7 +260,7 @@ inline ptzTYPES _convert_maptype(const char *str) { } // Internal parser - SubMapper (Individual Types of a Group) -ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { +ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL;; @@ -312,7 +317,7 @@ ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { // Recursion retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, (type_value == ptzLIST_DICT ? value : NULL), - _do_dmitypemap_parsing(ptr_n->children->next)); + _do_dmimap_parsing_typeid(ptr_n->children->next)); } else { char *tmpstr = NULL; @@ -353,11 +358,70 @@ ptzMAP *_do_dmitypemap_parsing(xmlNode *node) { return retmap; } + +xmlNode *_dmiMAP_GetRootElement(xmlDoc *mapdoc) { + xmlNode *rootnode = NULL; + + // Find the root tag and locate our mapping + rootnode = xmlDocGetRootElement(mapdoc); + assert( rootnode != NULL ); + + // Verify that the root node got the right name + if( (rootnode == NULL) + || (xmlStrcmp(rootnode->name, (xmlChar *) "dmidecode_mapping") != 0 )) { + PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); + return NULL; + } + + // Verify that it's of a version we support + if( strcmp(dmixml_GetAttrValue(rootnode, "version"), "1") != 0 ) { + PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + return NULL; + } + return rootnode; +} + + +ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) { + xmlNode *node = NULL; + + assert( mapnode != NULL); + + // Find the tag with our type ID + node = dmixml_FindNodeByAttr(mapnode, "TypeMap", "id", typeid); + if( node == NULL ) { + char msg[8194]; + snprintf(msg, 8193, "No mapping for type ID '%s' was found " + "in the XML-Python mapping file%c", typeid, 0); + PyErr_SetString(PyExc_IOError, msg); + return NULL; + } + // Create an internal map structure and return this structure + return _do_dmimap_parsing_typeid(node); +} + + +// Main parser function for the mapping XML +ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *mapname) { + xmlNode *node = NULL; + + node = _dmiMAP_GetRootElement(xmlmap); + if( node == NULL ) { + return NULL; + } + + // Find the section + node = dmixml_FindNode(node, "TypeMapping"); + assert( node != NULL ); + return _dmimap_parse_mapping_node_typeid(node, mapname); +} + + // Internal parser - Mapper (Groups of Types) -ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap) { +ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { ptzMAP *retmap = NULL; - ptzMAP *tmp = NULL; - xmlNode *ptr_n = NULL, *map_n = NULL;; + xmlNode *ptr_n = NULL, *map_n = NULL, *typemap = NULL; + char *type_id; // Go to the next XML_ELEMENT_NODE for( map_n = node; map_n != NULL; map_n = map_n->next ) { @@ -366,34 +430,43 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap) { } } if( map_n == NULL ) { + PyErr_SetString(PyExc_IOError, "Could not find any valid XML nodes"); return NULL; } - // Go to the first node - if( xmlStrcmp(node->name, (xmlChar *) "TypeMap") != 0 ) { - map_n = dmixml_FindNode(node, "TypeMap"); - if( map_n == NULL ) { - return NULL; - } + // Check that our "root" node is as expected + if( xmlStrcmp(node->name, (xmlChar *) "Mapping") != 0 ) { + PyErr_SetString(PyExc_IOError, "Could not find any valid XML nodes"); + return NULL; } - // Loop through it's children - xmlNode *typemap = dmixml_FindNode(xmlDocGetRootElement(xmlmap), "TypeMapping"); + // Go to the first node + map_n = dmixml_FindNode(node, "TypeMap"); + if( map_n == NULL ) { + return NULL; + } + + // Get the root element of the tag, needed for further parsing + typemap = dmixml_FindNode(xmlDocGetRootElement(xmlmap), "TypeMapping"); assert( typemap != NULL ); - char *type_id; + // Loop through it's children for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { //. TODO: Dazo: I had to add this (if() statement), but not sure why I should need to //. TODO: Needs investigation... - type_id = dmixml_GetAttrValue(ptr_n, "id"); - if(type_id) { - map_n = dmixml_FindNodeByAttr(typemap, "id", type_id); - if( tmp != NULL) { - tmp->next = _do_dmitypemap_parsing(map_n); - tmp = tmp->next; - } else { - retmap = _do_dmitypemap_parsing(map_n); - tmp = retmap; + + // Validate if we have the right node name + if( xmlStrcmp(ptr_n->name, (xmlChar *) "TypeMap") != 0 ) { + continue; // Skip unexpected tag names + } + + // Make sure that we have an id attribute before trying to locate that in th + if( (type_id = dmixml_GetAttrValue(ptr_n, "id")) != NULL) { + ptzMAP *map = NULL; + + map = _dmimap_parse_mapping_node_typeid(typemap, type_id); + if( map ) { + retmap = ptzmap_AppendMap(retmap, map); } } } @@ -401,68 +474,37 @@ ptzMAP *_do_dmimap_parsing(xmlNode *node, xmlDoc *xmlmap) { } - // Main parser function for the mapping XML -ptzMAP *dmiMAP_ParseMappingXML(xmlDoc *xmlmap, const char *mapname) { - ptzMAP *map = NULL; +ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; - int type_id = is_int(mapname); - - // Find the root tag and locate our mapping - node = xmlDocGetRootElement(xmlmap); - assert( node != NULL ); - - // Verify that the root node got the right name - if( (node == NULL) - || (xmlStrcmp(node->name, (xmlChar *) "dmidecode_mapping") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); - return NULL; - } - - // Verify that it's of a version we support - if( strcmp(dmixml_GetAttrValue(node, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); + // Validate the XML mapping document and get the root element + node = _dmiMAP_GetRootElement(xmlmap); + if( node == NULL ) { + PyErr_SetString(PyExc_IOError, "No valid mapping XML recieved"); return NULL; } - if(type_id > -1) { - node = dmixml_FindNode(node, "TypeMapping"); - assert( node != NULL ); - - char type_id_hex[5]; - snprintf(type_id_hex, 5, "0x%02x", type_id); - node = dmixml_FindNodeByAttr(node, "id", type_id_hex); - } else { - node = dmixml_FindNode(node, "GroupMapping"); - assert( node != NULL ); - - // Find the section matching our request (mapname) - for( node = node->children->next; node != NULL; node = node->next ) { - if( xmlStrcmp(node->name, (xmlChar *) "Mapping") == 0) { - char *name = dmixml_GetAttrValue(node, "name"); - if( (name != NULL) && (strcmp(name, mapname) == 0) ) { - break; - } - } - } - } + // Find the section + node = dmixml_FindNode(node, "GroupMapping"); + assert( node != NULL ); + // Find the section matching our request (mapname) + node = dmixml_FindNodeByAttr(node, "Mapping", "name", mapname); if( node == NULL ) { char msg[8194]; - snprintf(msg, 8193, "No mapping for '%s' was found " + snprintf(msg, 8193, "No group mapping for '%s' was found " "in the XML-Python mapping file%c", mapname, 0); PyErr_SetString(PyExc_IOError, msg); return NULL; } - // Start creating an internal map structure based on the mapping XML. - map = (type_id == -1) ? _do_dmimap_parsing(node, xmlmap) : _do_dmitypemap_parsing(node); - - return map; + // Create an internal map structure and return this structure + return _do_dmimap_parsing_group(node, xmlmap); } + // // Parser routines for converting XML data into Python structures // @@ -904,7 +946,7 @@ PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) } -#if 0 +#if 1 // Simple independent main function - only for debugging int main(int argc, char **argv) { xmlDoc *doc = NULL, *data = NULL; @@ -913,18 +955,21 @@ int main(int argc, char **argv) { Py_Initialize(); - doc = xmlReadFile("pythonmap.xml", NULL, 0); + doc = xmlReadFile("pymap.xml", NULL, 0); assert( doc != NULL ); - map = dmiMAP_ParseMappingXML(doc, argv[1]); + // map = dmiMAP_ParseMappingXML_GroupName(doc, argv[1]); + map = dmiMAP_ParseMappingXML_TypeID(doc, argv[1]); ptzmap_Dump(map); printf("----------------------\n"); - + assert(map != NULL); data = xmlReadFile(argv[2], NULL, 0); assert( data != NULL ); pydat = pythonizeXMLdoc(map, data); + assert( pydat != NULL ); + Py_INCREF(pydat); printf("\n\n"); PyObject_Print(pydat, stdout, 0); -- cgit From 4e39cec61e7434f4826533220bbe5870a4300baa Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 2 Jun 2009 16:17:52 +0200 Subject: Replaced all 'for' iterations on xmlNodes with 'foreach_xmlnode' --- src/xmlpythonizer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index f1ecee7..3ba3e80 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -171,7 +171,7 @@ void ptzmap_Free_func(ptzMAP *ptr) } -#if 1 +#if 0 // DEBUG FUNCTIONS static const char *ptzTYPESstr[] = { "ptzCONST", "ptzSTR", "ptzINT", "ptzFLOAT", "ptzBOOL", "ptzLIST_STR", "ptzLIST_INT", "ptzLIST_FLOAT", "ptzLIST_BOOL", @@ -265,7 +265,7 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { xmlNode *ptr_n = NULL, *map_n = NULL;; // Go to the next XML_ELEMENT_NODE - for( map_n = node; map_n != NULL; map_n = map_n->next ) { + foreach_xmlnode(node, map_n) { if( map_n->type == XML_ELEMENT_NODE ) { break; } @@ -283,7 +283,7 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { } // Loop through it's children - for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { + foreach_xmlnode(map_n, ptr_n) { ptzTYPES type_key, type_value; char *key = NULL, *value = NULL; char *rootpath = NULL; @@ -424,7 +424,7 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { char *type_id; // Go to the next XML_ELEMENT_NODE - for( map_n = node; map_n != NULL; map_n = map_n->next ) { + foreach_xmlnode(node, map_n) { if( map_n->type == XML_ELEMENT_NODE ) { break; } @@ -451,7 +451,7 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { assert( typemap != NULL ); // Loop through it's children - for( ptr_n = map_n ; ptr_n != NULL; ptr_n = ptr_n->next ) { + foreach_xmlnode(map_n, ptr_n) { //. TODO: Dazo: I had to add this (if() statement), but not sure why I should need to //. TODO: Needs investigation... @@ -887,7 +887,7 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { // Loop through all configured elements retdata = PyDict_New(); - for( map_p = in_map; map_p != NULL; map_p = map_p->next ) { + foreach_xmlnode(in_map, map_p) { if( (map_p->type_value == ptzDICT) && (map_p->rootpath != NULL) ) { xmlXPathObject *xpo = NULL; int i; @@ -946,7 +946,7 @@ PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) } -#if 1 +#if 0 // Simple independent main function - only for debugging int main(int argc, char **argv) { xmlDoc *doc = NULL, *data = NULL; @@ -958,8 +958,8 @@ int main(int argc, char **argv) { doc = xmlReadFile("pymap.xml", NULL, 0); assert( doc != NULL ); - // map = dmiMAP_ParseMappingXML_GroupName(doc, argv[1]); - map = dmiMAP_ParseMappingXML_TypeID(doc, argv[1]); + map = dmiMAP_ParseMappingXML_GroupName(doc, argv[1]); + // map = dmiMAP_ParseMappingXML_TypeID(doc, argv[1]); ptzmap_Dump(map); printf("----------------------\n"); assert(map != NULL); -- cgit From eb33e79cb5eae7da473347a4f79dc07d4e91ceff Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 2 Jun 2009 19:47:44 +0200 Subject: Updated comments for all functions in xmlpythonizer.c in Doxygen format --- src/xmlpythonizer.c | 198 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 171 insertions(+), 27 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 3ba3e80..74b7db3 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -60,6 +60,15 @@ * are deemed to be part of the source code. */ +/** + * @file xmlpythonizer.c + * @brief Generic parser for converting XML documents or XML nodes + * into Python Dictionaries + * @author David Sommerseth + * @author Nima Talebi + */ + + #include #include @@ -75,13 +84,37 @@ #include "xmlpythonizer.h" -ptzMAP *ptzmap_AppendMap(const ptzMAP *chain, ptzMAP *newmap) { +/** + * This functions appends a new ptzMAP structure to an already existing chain + * @author David Sommerseth + * @param ptzMAP* Pointer to the chain the new ptzMAP is to be appended + * @param ptzMAP* Pointer to the new ptzMAP to be appended to the already existing ptzMAP + * @return ptzMAP* Pointer to the ptzMAP which includes the newly added ptzMAP + */ +ptzMAP *ptzmap_AppendMap(const ptzMAP *chain, ptzMAP *newmap) +{ if( chain != NULL ) { newmap->next = (ptzMAP *) chain; } return newmap; } + +/** + * This function creates a new ptzMAP mapping record. This defines the key/value relationship in + * the resulting Python Dictionaries. + * @author David Sommerseth + * @param ptzMAP* Pointer to the chain the new mapping will be appended + * @param char* XPath root of the given key and value XPath expressions. + * If NULL, the key and value XPath expressions must be absolute. + * @param ptzTYPES Type of the 'key' value + * @param const char* XPath expression or constant string for the 'key' value + * @param ptzTYPES Type of the 'value' value + * @param const char* XPath expression or constant string for the 'value' value + * @param ptzMAP* Used if the value type is of one of the ptzDICT types, contains a new + * mapping level for the children + * @return ptzMAP* Pointer to the ptzMAP which includes the newly added ptzMAP + */ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, ptzTYPES ktyp, const char *key, ptzTYPES vtyp, const char *value, @@ -115,7 +148,16 @@ ptzMAP *ptzmap_Add(const ptzMAP *chain, char *rootp, return ptzmap_AppendMap(chain, ret); }; -void ptzmap_SetFixedList(ptzMAP *map_p, const char *index, int size) { + +/** + * This functions sets an ptzLIST typed map entry as a fixed list + * @author David Sommerseth + * @param ptzMAP* Pointer to the ptzMAP elemnt to be updated + * @param const char* Attribute name of the XML node of the 'key' to use as the list index + * @param int Defines the size of the list + */ +void ptzmap_SetFixedList(ptzMAP *map_p, const char *index, int size) +{ assert( map_p != NULL ); switch( map_p->type_value ) { @@ -132,6 +174,12 @@ void ptzmap_SetFixedList(ptzMAP *map_p, const char *index, int size) { } } + +/** + * This functions frees up a complete pointer chain. This is normally called via #define ptzmap_Free() + * @author David Sommerseth + * @param ptzMAP* Pointer to the ptzMAP to free + */ void ptzmap_Free_func(ptzMAP *ptr) { if( ptr == NULL ) { @@ -189,6 +237,7 @@ void indent(int lvl) } } + #define ptzmap_Dump(ptr) { ptzmap_Dump_func(ptr, 0); } void ptzmap_Dump_func(const ptzMAP *ptr, int level) { @@ -221,15 +270,13 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) } #endif // END OF DEBUG FUNCTIONS -// -// Parser for the XML -> Python mapping XML file -// -// This mappipng XML file describes how the Python result -// should look like and where it should pick the data from -// when later on parsing the dmidecode XML data. -// -// Valid key and value types for the mapping file +/** + * This functions converts a string to valid ptzTYPES values. This is used when parsing the XML mapping nodes + * @author David Sommerseth + * @param const char* String value containing the key/value type + * @return ptzTYPES The type value + */ inline ptzTYPES _convert_maptype(const char *str) { if( strcmp(str, "string") == 0 ) { return ptzSTR; @@ -259,7 +306,13 @@ inline ptzTYPES _convert_maptype(const char *str) { } } -// Internal parser - SubMapper (Individual Types of a Group) + +/** + * This functions is the internal parser - SubMapper (Individual Types of a Group) + * @author David Sommerseth + * @param xmlNode* Node of the starting point for the parsing + * @return ptzMAP* The ptzMAP version of the XML definition + */ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL;; @@ -358,7 +411,12 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { return retmap; } - +/** + * This functions validates and retrieves the root node of the dmidecode_mapping XML node from an XML document + * @author David Sommerseth + * @param xmlDoc* XML mapping document pointer + * @return xmlNode* The root xmlNode of a valid XML mapping document. On invalid document NULL is returned. + */ xmlNode *_dmiMAP_GetRootElement(xmlDoc *mapdoc) { xmlNode *rootnode = NULL; @@ -382,6 +440,14 @@ xmlNode *_dmiMAP_GetRootElement(xmlDoc *mapdoc) { } +/** + * Internal function which looks up the given Type ID among TypeMap nodes and and parses + * the found XML nodes into a ptzMAP + * @author David Sommerseth + * @param xmlNode* The node where the TypeMapping tags are found + * @param const char* The typeid to parse to a ptzMAP + * @return ptzMAP* The parsed result of the XML nodes + */ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) { xmlNode *node = NULL; @@ -401,7 +467,13 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) } -// Main parser function for the mapping XML +/** + * Exported function for parsing a XML mapping document for a given Type ID to a ptzMAP + * @author David Sommerseth + * @param xmlDoc* Pointer to the XML mapping document + * @param const char* The Type ID to create the map for + * @return ptzMAP* The parsed XML containing as a ptzMAP + */ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; @@ -417,7 +489,15 @@ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *mapname) { } -// Internal parser - Mapper (Groups of Types) +/** + * Internal parser for GroupMapping (group of types). Converts a given GroupMapping to a ptzMAP + * from a XML node set + * @author Nima Talebi + * @author David Sommerseth + * @param xmlNode* The source XML nodes of what to parse to a ptzMAP + * @param xmlDoc* A pointer to the source map, used for further parsing of each type defined in the GroupMapping + * @return ptzMAP* The resulting ptzMAP of the parsed xmlNode group mapping + */ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL, *typemap = NULL; @@ -452,9 +532,6 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { // Loop through it's children foreach_xmlnode(map_n, ptr_n) { - //. TODO: Dazo: I had to add this (if() statement), but not sure why I should need to - //. TODO: Needs investigation... - // Validate if we have the right node name if( xmlStrcmp(ptr_n->name, (xmlChar *) "TypeMap") != 0 ) { continue; // Skip unexpected tag names @@ -474,7 +551,14 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { } -// Main parser function for the mapping XML +/** + * Exported function which parses a given GroupMapping (consisting of + * one or more TypeMaps) into a ptzMAP + * @author David Sommerseth + * @param xmlDoc* Pointer to the XML document holding the mapping + * @param const char* Defines which group mapping to parse to a ptzMAP + * @return ptzMAP* The parsed XML mapping in a ptzMAP + */ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; @@ -504,10 +588,13 @@ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { } - -// -// Parser routines for converting XML data into Python structures -// +/** + * Internal function for converting a given mapped value to the appropriate Python data type + * @author David Sommerseth + * @param ptzMAP* Pointer to the current mapping entry being parsed + * @param const char * String which contains the value to be converted to a Python value + * @return PyObject * The converted value as a Python object + */ inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { PyObject *value; const char *workstr = NULL; @@ -577,7 +664,15 @@ inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { return value; } -// Retrieve a value from the XML doc (XPath Context) based on a XPath query + +/** + * Retrieves a value from the data XML doc (via XPath Context) based on a XPath query + * @author David Sommerseth + * @param xmlXPathContext* Pointer to the XPath context holding the source data + * @param const char* The XPath expression where to find the data + * @return xmlXPathObject* If data is found, it is returned in an XPath object for further processing + */ + xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { xmlChar *xp_xpr = NULL; xmlXPathObject *xp_obj = NULL; @@ -594,6 +689,18 @@ xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { return xp_obj; } + +/** + * Retrieves the value which is to be used as the key value in a Python dictionary. + * @author David Sommerseth + * @param char* Pointer to the return buffer for the value + * @param size_t Size of the return buffer + * @param ptzMAP* Pointer to the current mapping entry which is being parsed + * @param xmlXPathContext* Pointer to the XPath context containing the source data + * @param int Defines which of the XPath results to use, if more is found + * @returns char* Returns a pointer to the return buffer (parameter 1) if key value + * is found, or NULL if not found + */ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { xmlXPathObject *xpobj = NULL; @@ -628,12 +735,29 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x } +/** + * Simple define to properly add a key/value pair to a Python dictionary + * @author David Sommerseth + * @param PyObject* Pointer to the Python dictionary to be updated + * @param const char* String containing the key value + * @param PyObject* Pointer to the Python value + */ #define PyADD_DICT_VALUE(p, k, v) { \ PyDict_SetItemString(p, k, v); \ Py_DECREF(v); \ } + +/** + * Internal function for adding a XPath result to the resulting Python dictionary + * @author David Sommerseth + * @param PyObject* Pointer to the resulting Python dictionary + * @param xmlXPathContext* Pointer to the XPath context containing the source data + * (used for retrieving the key value) + * @param ptzMAP* Pointer to the current mapping entry being parsed + * @param xmlXPathObject* Pointer to XPath object containing the data value(s) for the dictionary + */ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *map_p, xmlXPathObject *value) { int i = 0; char *key = NULL; @@ -677,8 +801,17 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m } -// Internal XML parser routine, which traverses the given mapping table, -// returning a Python structure accordingly to the map. +/** + * Internal XML parser routine, which traverses the given mapping table, + * returning a Python structure accordingly to the map. Data for the Python dictionary is + * take from the input XML node. + * @author David Sommerseth + * @param PyObject* Pointer to the Python dictionary of the result + * @param ptzMAP* Pointer to the starting point for the further parsing + * @param xmlNode* Pointer to the XML node containing the source data + * @param int For debug purpose only, to keep track of which element being parsed + * @return PyObject* Pointer to the input Python dictionary + */ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int elmtid) { char *key = NULL; xmlXPathContext *xpctx = NULL; @@ -869,7 +1002,13 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int return retdata; } -// Convert a xmlNode to a Python object, based on the given map + +/** + * Exported function, for parsing a XML node to a Python dictionary based on the given ptzMAP + * @author David Sommerseth + * @param ptzMAP* The map descriping the resulting Python dictionary + * @param xmlNode* XML node pointer to the source data to be used for populating the Python dictionary + */ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xmlXPathContext *xpctx = NULL; xmlDoc *xpdoc = NULL; @@ -936,7 +1075,12 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { } -// Convert a xmlDoc to a Python object, based on the given map +/** + * Exported function, for parsing a XML document to a Python dictionary based on the given ptzMAP + * @author David Sommerseth + * @param ptzMAP* The map descriping the resulting Python dictionary + * @param xmlDoc* XML document pointer to the source data to be used for populating the Python dictionary + */ PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) { xmlNode *node = NULL; -- cgit From 4b22254e56bfdbec884a7f1cf634e340eff813c5 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 9 Jun 2009 16:09:22 +0200 Subject: Renamed _dmiMAP_GetRootElement(...) to dmiMAP_GetRootElement(...) and exported the function --- src/xmlpythonizer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 74b7db3..6c4d4c0 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -417,7 +417,7 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { * @param xmlDoc* XML mapping document pointer * @return xmlNode* The root xmlNode of a valid XML mapping document. On invalid document NULL is returned. */ -xmlNode *_dmiMAP_GetRootElement(xmlDoc *mapdoc) { +xmlNode *dmiMAP_GetRootElement(xmlDoc *mapdoc) { xmlNode *rootnode = NULL; // Find the root tag and locate our mapping @@ -477,7 +477,7 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; - node = _dmiMAP_GetRootElement(xmlmap); + node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { return NULL; } @@ -563,7 +563,7 @@ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; // Validate the XML mapping document and get the root element - node = _dmiMAP_GetRootElement(xmlmap); + node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { PyErr_SetString(PyExc_IOError, "No valid mapping XML recieved"); return NULL; -- cgit From f9589f45af460c82fac3712b0560de0e1dc6171d Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 9 Jun 2009 17:14:29 +0200 Subject: Pass typeid as int internally to the dmiMAP_ParseMappingXML_TypeID(...) This function will then convert the value to proper hex value for further processing. --- src/xmlpythonizer.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 6c4d4c0..f7fdb3c 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -474,18 +474,22 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) * @param const char* The Type ID to create the map for * @return ptzMAP* The parsed XML containing as a ptzMAP */ -ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, const char *mapname) { +ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { xmlNode *node = NULL; + char typeid_s[16]; node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { return NULL; } + memset(&typeid_s, 0, 16); + snprintf(typeid_s, 14, "0x%02x", typeid); + // Find the section node = dmixml_FindNode(node, "TypeMapping"); assert( node != NULL ); - return _dmimap_parse_mapping_node_typeid(node, mapname); + return _dmimap_parse_mapping_node_typeid(node, typeid_s); } @@ -1103,7 +1107,7 @@ int main(int argc, char **argv) { assert( doc != NULL ); map = dmiMAP_ParseMappingXML_GroupName(doc, argv[1]); - // map = dmiMAP_ParseMappingXML_TypeID(doc, argv[1]); + // map = dmiMAP_ParseMappingXML_TypeID(doc, atoi(rgv[1])); ptzmap_Dump(map); printf("----------------------\n"); assert(map != NULL); -- cgit From 80bf200604d80703f9ef02fe8a4a505b6cd96ab6 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 9 Jun 2009 20:33:20 +0200 Subject: Moved xmlpythonizer.c over to new error functions --- src/xmlpythonizer.c | 107 +++++++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 59 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index f7fdb3c..fbf01fd 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -81,6 +81,7 @@ #include "util.h" #include "dmixml.h" +#include "dmierror.h" #include "xmlpythonizer.h" @@ -324,13 +325,15 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { } } if( map_n == NULL ) { - return NULL; + PyReturnError(PyExc_NameError, "No mapping nodes were found"); } // Go to the first node if( xmlStrcmp(node->name, (xmlChar *) "Map") != 0 ) { map_n = dmixml_FindNode(node, "Map"); if( map_n == NULL ) { + // If we don't find a node, we just exit now. + // Other checks will raise an exception if needed. return NULL; } } @@ -427,14 +430,14 @@ xmlNode *dmiMAP_GetRootElement(xmlDoc *mapdoc) { // Verify that the root node got the right name if( (rootnode == NULL) || (xmlStrcmp(rootnode->name, (xmlChar *) "dmidecode_mapping") != 0 )) { - PyErr_SetString(PyExc_IOError, "Invalid XML-Python mapping file"); - return NULL; + PyReturnError(PyExc_IOError, "Invalid XML-Python mapping file. " + "Root node is not 'dmidecode_mapping'"); } // Verify that it's of a version we support if( strcmp(dmixml_GetAttrValue(rootnode, "version"), "1") != 0 ) { - PyErr_SetString(PyExc_IOError, "Unsupported XML-Python mapping file format"); - return NULL; + PyReturnError(PyExc_RuntimeError, "Unsupported XML-Python mapping file format. " + "Only version 1 is supported"); } return rootnode; } @@ -456,10 +459,9 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) // Find the tag with our type ID node = dmixml_FindNodeByAttr(mapnode, "TypeMap", "id", typeid); if( node == NULL ) { - char msg[8194]; - snprintf(msg, 8193, "No mapping for type ID '%s' was found " - "in the XML-Python mapping file%c", typeid, 0); - PyErr_SetString(PyExc_IOError, msg); + // No exception handling possible here, as we don't return PyObject + fprintf(stderr,"** WARNING: Could not find any XML->Python " + "mapping for type ID '%s'", typeid); return NULL; } // Create an internal map structure and return this structure @@ -480,7 +482,7 @@ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { - return NULL; + PyReturnError(PyExc_RuntimeError, "Could not locate root XML node for mapping file"); } memset(&typeid_s, 0, 16); @@ -514,25 +516,25 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { } } if( map_n == NULL ) { - PyErr_SetString(PyExc_IOError, "Could not find any valid XML nodes"); - return NULL; + PyReturnError(PyExc_RuntimeError, "Could not find any valid XML nodes"); } // Check that our "root" node is as expected if( xmlStrcmp(node->name, (xmlChar *) "Mapping") != 0 ) { - PyErr_SetString(PyExc_IOError, "Could not find any valid XML nodes"); - return NULL; + PyReturnError(PyExc_NameError, "Expected to find node"); } // Go to the first node map_n = dmixml_FindNode(node, "TypeMap"); if( map_n == NULL ) { - return NULL; + PyReturnError(PyExc_NameError, "Could not locate any nodes"); } // Get the root element of the tag, needed for further parsing typemap = dmixml_FindNode(xmlDocGetRootElement(xmlmap), "TypeMapping"); - assert( typemap != NULL ); + if( typemap == NULL ) { + PyReturnError(PyExc_NameError, "Could not locate the node"); + } // Loop through it's children foreach_xmlnode(map_n, ptr_n) { @@ -569,22 +571,20 @@ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { // Validate the XML mapping document and get the root element node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { - PyErr_SetString(PyExc_IOError, "No valid mapping XML recieved"); - return NULL; + PyReturnError(PyExc_RuntimeError, "No valid mapping XML recieved"); } // Find the section node = dmixml_FindNode(node, "GroupMapping"); - assert( node != NULL ); + if( node == NULL ) { + PyReturnError(PyExc_NameError, "Could not find the node"); + } // Find the section matching our request (mapname) node = dmixml_FindNodeByAttr(node, "Mapping", "name", mapname); if( node == NULL ) { - char msg[8194]; - snprintf(msg, 8193, "No group mapping for '%s' was found " - "in the XML-Python mapping file%c", mapname, 0); - PyErr_SetString(PyExc_IOError, msg); - return NULL; + PyReturnError(PyExc_NameError, "No group mapping for '%s' was found " + "in the XML-Python mapping file", mapname); } // Create an internal map structure and return this structure @@ -842,10 +842,8 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int value = PyString_FromString(map_p->value); PyADD_DICT_VALUE(retdata, key, value); } else { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", - map_p->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); + PyReturnError(PyExc_ValueError, "Could not get key value: %s [%i] (Defining key: %s)", + map_p->rootpath, elmtid, map_p->key); } break; @@ -907,11 +905,9 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int PyADD_DICT_VALUE(retdata, key, value); xmlXPathFreeObject(xpo); } else { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: " - "%s [%i] (Defining key: %s)%c", - map_p->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); + PyReturnError(PyExc_ValueError, "Could not get key value: " + "%s [%i] (Defining key: %s)", + map_p->rootpath, elmtid, map_p->key); } } break; @@ -922,11 +918,9 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int break; } if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", - map_p->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - break; + PyReturnError(PyExc_ValueError, + "Could not get key value: %s [%i] (Defining key: %s)", + map_p->rootpath, elmtid, map_p->key); } // Use recursion when procession child elements value = pythonizeXMLnode(map_p->child, data_n); @@ -938,25 +932,20 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int break; } if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { - char msg[8094]; - snprintf(msg, 8092, "Could not get key value: %s [%i] (Defining key: %s)%c", - map_p->rootpath, elmtid, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - break; + PyReturnError(PyExc_ValueError, + "Could not get key value: %s [%i] (Defining key: %s)", + map_p->rootpath, elmtid, map_p->key); } // Iterate all nodes which is found in the 'value' XPath xpo = _get_xpath_values(xpctx, map_p->value); if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { - char msg[8094]; - snprintf(msg, 8092, "Could not locate XML path node (e1): %s (Defining key: %s)%c", - map_p->value, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - if( xpo != NULL ) { xmlXPathFreeObject(xpo); } - break; + PyReturnError(PyExc_ValueError, + "Could not get key value: %s [%i] (Defining key: %s)", + map_p->rootpath, elmtid, map_p->key); } // Prepare a data list @@ -1021,12 +1010,13 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { char *key = NULL; if( (in_map == NULL) || (data_n == NULL) ) { - PyErr_SetString(PyExc_LookupError, "XMLnode or map is NULL"); - return NULL; + PyReturnError(PyExc_RuntimeError, "pythonXMLnode() - xmlNode or ptzMAP is NULL"); } key = (char *) malloc(258); - assert( key != NULL ); + if( key == NULL ) { + PyReturnError(PyExc_MemoryError, "Could not allocate temporary buffer"); + } // Loop through all configured elements retdata = PyDict_New(); @@ -1041,22 +1031,21 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xmlDocSetRootElement(xpdoc, xmlCopyNode(data_n, 1)); xpctx = xmlXPathNewContext(xpdoc); - assert( xpctx != NULL ); + if( xpctx == NULL ) { + PyReturnError(PyExc_MemoryError, "Could not setup new XPath context"); + } xpctx->node = data_n; xpo = _get_xpath_values(xpctx, map_p->rootpath); if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { - char msg[8094]; //XXX - snprintf(msg, 8092, "Could not locate XML path node (e2): %s (Defining key: %s)%c", - map_p->rootpath, map_p->key, 0); - PyErr_SetString(PyExc_LookupError, msg); - if( xpo != NULL ) { xmlXPathFreeObject(xpo); } xmlFreeDoc(xpdoc); xmlXPathFreeContext(xpctx); - return NULL; + PyReturnError(PyExc_LookupError, + "Could not locate XML path node (e2): %s " + "(Defining key: %s)", map_p->rootpath, map_p->key); } for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { -- cgit From 19a78f3ec9dd41298f8e84dbf58da71901b42c6c Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 9 Jun 2009 21:16:21 +0200 Subject: Don't set exceptions when it should already be set --- src/xmlpythonizer.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index fbf01fd..68c29c2 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -968,7 +968,6 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int // If we have a fixed list and we have a index value for the list if( (map_p->fixed_list_size > 0) && (map_p->list_index != NULL) ) { char *idx = NULL; - idx = dmixml_GetAttrValue(xpo->nodesetval->nodeTab[i], map_p->list_index); if( idx != NULL ) { @@ -978,6 +977,9 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int // No list index - append the value PyList_Append(value, dataset); } + } else { + // If NULL, something is wrong - exception is already set. + return NULL; } } PyADD_DICT_VALUE(retdata, key, value); @@ -1052,15 +1054,25 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xpctx->node = xpo->nodesetval->nodeTab[i]; if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - _deep_pythonize(retdata, map_p, - xpo->nodesetval->nodeTab[i], i); + PyObject *res = _deep_pythonize(retdata, map_p, + xpo->nodesetval->nodeTab[i], i); + if( res == NULL ) { + // Exit if we get NULL - something is wrong + //and exception is set + return NULL; + } } } xmlXPathFreeObject(xpo); xmlXPathFreeContext(xpctx); xmlFreeDoc(xpdoc); } else { - _deep_pythonize(retdata, map_p, data_n, 0); + PyObject *res = _deep_pythonize(retdata, map_p, data_n, 0); + if( res == NULL ) { + // Exit if we get NULL - something is wrong + //and exception is set + return NULL; + } } } free(key); -- cgit From 0bad177cda15cf21ab5bb7f1ea9eaf736d0f1ba7 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 11 Jun 2009 15:34:14 +0200 Subject: Pick the version info from version.h --- src/xmlpythonizer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 68c29c2..f6dfe15 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -83,6 +83,7 @@ #include "dmixml.h" #include "dmierror.h" #include "xmlpythonizer.h" +#include "version.h" /** @@ -1172,7 +1173,7 @@ PyMODINIT_FUNC initxmlpythonizer(void) { Py_InitModule3((char *)"xmlpythonizer", DemoMethods, "XML to Python Proof-of-Concept Python Module"); - PyObject *version = PyString_FromString("3.10.6"); + PyObject *version = PyString_FromString(VERSION); Py_INCREF(version); PyModule_AddObject(module, "version", version); } -- cgit From 20030e42b4d3f7283f6143641cb009a8dbf1da24 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 15 Jun 2009 11:07:34 +0200 Subject: Fixed wrong int->hex string conversion Upper case hex string values is used in the pymap.xml file. This should be improved so that type id is case insensitive. --- src/xmlpythonizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index f6dfe15..bf3d323 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -487,7 +487,7 @@ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { } memset(&typeid_s, 0, 16); - snprintf(typeid_s, 14, "0x%02x", typeid); + snprintf(typeid_s, 14, "0x%02X", typeid); // Find the section node = dmixml_FindNode(node, "TypeMapping"); -- cgit From e9a6b7f9ec31c1227be982fb8f2bb0ee8bf97710 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 15 Jun 2009 11:11:55 +0200 Subject: Fixed wrong behavivour in pythonizeXMLnode() when no key value is found If the XPath expression for the key value points on a non-existing XML node, it would earlier abort pythonizing the XML data. Even though this could look like the correct behaviour, it will not work out well in reality. For sections like 'bios', it might be that the DMI/SMBIOS data do not describe or provide the BIOSLanguage section (type id 0x0D). Which means calling dmidecode.bios() would fail completely instead of reporting what it could find. This patch fixes this issue and it will normally ignore not found key values and just continue pythonizing the XML data and return what it managed to translate into a Python dictionary. If DEBUG is defined when compiling python-dmidecode, a warning message will be printed directly to stderr when a key value is not found. A warning is printed if dmidecode is compiled with DEBUG defined. --- src/xmlpythonizer.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index bf3d323..a9282e2 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -1040,33 +1040,32 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xpctx->node = data_n; xpo = _get_xpath_values(xpctx, map_p->rootpath); - if( (xpo == NULL) || (xpo->nodesetval == NULL) || (xpo->nodesetval->nodeNr == 0) ) { - if( xpo != NULL ) { - xmlXPathFreeObject(xpo); + if( (xpo != NULL) && (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr > 0) ) { + for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { + xpctx->node = xpo->nodesetval->nodeTab[i]; + + if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + PyObject *res = _deep_pythonize(retdata, map_p, + xpo->nodesetval->nodeTab[i], i); + if( res == NULL ) { + // Exit if we get NULL - something is wrong + //and exception is set + return NULL; + } + } } - xmlFreeDoc(xpdoc); xmlXPathFreeContext(xpctx); - PyReturnError(PyExc_LookupError, - "Could not locate XML path node (e2): %s " - "(Defining key: %s)", map_p->rootpath, map_p->key); + xmlFreeDoc(xpdoc); } - - for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { - xpctx->node = xpo->nodesetval->nodeTab[i]; - - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - PyObject *res = _deep_pythonize(retdata, map_p, - xpo->nodesetval->nodeTab[i], i); - if( res == NULL ) { - // Exit if we get NULL - something is wrong - //and exception is set - return NULL; - } - } +#ifdef DEBUG + else { + fprintf(stderr, "** pythonizeXMLnode :: Could not locate node for key value: " + "root path '%s', key '%s'\n", map_p->rootpath, map_p->key); + } +#endif + if( xpo != NULL ) { + xmlXPathFreeObject(xpo); xpo = NULL; } - xmlXPathFreeObject(xpo); - xmlXPathFreeContext(xpctx); - xmlFreeDoc(xpdoc); } else { PyObject *res = _deep_pythonize(retdata, map_p, data_n, 0); if( res == NULL ) { -- cgit From 655799b06376c503086e43a0225298d170e08dbf Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 15 Jun 2009 18:39:49 +0200 Subject: Added new function: dmixml_FindNodeByAttr_NoCase(...) This function will ignore the case of the string of the value to be found. This improves the behaviour mentioned in commit 20030e42b4d3f7283f6143641cb009a8dbf1da24. At the moment, the immediate advantage is that the pymap.xml is not strictly bound to if the type IDs in hex are in upper and/or lower case. Both cases and mixed cases will now work. --- src/xmlpythonizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index a9282e2..47590dd 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -458,7 +458,7 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) assert( mapnode != NULL); // Find the tag with our type ID - node = dmixml_FindNodeByAttr(mapnode, "TypeMap", "id", typeid); + node = dmixml_FindNodeByAttr_NoCase(mapnode, "TypeMap", "id", typeid); if( node == NULL ) { // No exception handling possible here, as we don't return PyObject fprintf(stderr,"** WARNING: Could not find any XML->Python " -- cgit From d7376531310a92837dff47f9b0b130bb529c490b Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 19 Jun 2009 11:14:47 +0200 Subject: Fixed missing check which caused SEGV on Python2.3 Could also be related to an older libxml2 version as well, as this behaviour was found on RHEL4u4 --- src/xmlpythonizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 47590dd..6704d1b 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -866,7 +866,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int xpo = _get_xpath_values(xpctx, map_p->value); if( xpo != NULL ) { if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - if( xpo->nodesetval->nodeNr > 0 ) { + if( (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr > 0) ) { value = PyList_New(0); // If we're working on a fixed list, create one which contains -- cgit From 9c651823c9d4bb918c7b7bb618a3a6275ee22619 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 19 Jun 2009 11:16:08 +0200 Subject: Fixed incorrectly Py_DECREC() on Py_None values --- src/xmlpythonizer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/xmlpythonizer.c') diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index 6704d1b..ba018eb 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -748,9 +748,11 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x * @param PyObject* Pointer to the Python value */ -#define PyADD_DICT_VALUE(p, k, v) { \ - PyDict_SetItemString(p, k, v); \ - Py_DECREF(v); \ +#define PyADD_DICT_VALUE(p, k, v) { \ + PyDict_SetItemString(p, k, v); \ + if( v != Py_None ) { \ + Py_DECREF(v); \ + } \ } -- cgit