7

I am working on a parser to get data from an XML file. I am using libxml2 to extract data. I am a not able to get the attributes from nodes. I only found nb_attributes to get the count of the attributes.

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
kiri
  • 1,977
  • 5
  • 27
  • 55

6 Answers6

15

I think joostk meant attribute->children, giving something like this:

xmlAttr* attribute = node->properties;
while(attribute)
{
  xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
  //do something with value
  xmlFree(value); 
  attribute = attribute->next;
}

See if that works for you.

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
Matthew Lowe
  • 1,350
  • 1
  • 17
  • 29
  • Hi Mat. I found your code helpful in finding out the values of attribute. But it gives the value for only the first node. How to get values for the following nodes also. ??.. Thanks in advance. – NiKKi Jun 01 '12 at 09:30
  • You can iterate over nodes the same way you iterate over attributes: node = node->next. – Matthew Lowe Jun 02 '12 at 19:51
9

if you just want a single attribute, use xmlGetProp or xmlGetNsProp

Bevan Collins
  • 1,531
  • 16
  • 25
5

I think I found why you only got 1 attribute (at least it happened to me).

The problem was that I read attributes for first node but next is a text node. Don't know why, but node->properties gives me a reference to a non-readable part of memory, so it crashed.

My solution was to check node type (element is 1)

I'm using a reader, so:

xmlTextReaderNodeType(reader)==1

The entire code you can get it from http://www.xmlsoft.org/examples/reader1.c and add this

xmlNodePtr node= xmlTextReaderCurrentNode(reader);
if (xmlTextReaderNodeType(reader)==1 && node && node->properties) {
    xmlAttr* attribute = node->properties;
    while(attribute && attribute->name && attribute->children)
    {
      xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
      printf ("Atributo %s: %s\n",attribute->name, value);
      xmlFree(value);
      attribute = attribute->next;
    }
}

to line 50.

tiparega
  • 51
  • 1
  • 1
1

Try something like:

xmlNodePtr node; // Some node
NSMutableArray *attributes = [NSMutableArray array];

for(xmlAttrPtr attribute = node->properties; attribute != NULL; attribute = attribute->next){
    xmlChar *content = xmlNodeListGetString(node->doc, attribute->children, YES);
    [attributes addObject:[NSString stringWithUTF8String:content]];
    xmlFree(content);
}
Joost
  • 10,333
  • 4
  • 55
  • 61
  • Hi Mat. I found your code helpful in finding out the values of attribute. But it gives the value for only the first node. How to get values for the following nodes also. ??.. Thanks in advance. – NiKKi Jun 01 '12 at 09:31
  • Shouldn't `node-children` become `attribute->children`? – Rudolf Adamkovič Apr 20 '13 at 09:58
  • Yes it should :) Also see @Matthew Lowe, he noticed the mistake earlier. I've updated the answer (2.5 years later ;)) – Joost Apr 21 '13 at 00:22
0

If you use SAX method startElementNs(...), this function is what you are looking for:

xmlChar *getAttributeValue(char *name, const xmlChar ** attributes,
           int nb_attributes)
{
int i;
const int fields = 5;    /* (localname/prefix/URI/value/end) */
xmlChar *value;
size_t size;
for (i = 0; i < nb_attributes; i++) {
    const xmlChar *localname = attributes[i * fields + 0];
    const xmlChar *prefix = attributes[i * fields + 1];
    const xmlChar *URI = attributes[i * fields + 2];
    const xmlChar *value_start = attributes[i * fields + 3];
    const xmlChar *value_end = attributes[i * fields + 4];
    if (strcmp((char *)localname, name))
        continue;
    size = value_end - value_start;
    value = (xmlChar *) malloc(sizeof(xmlChar) * size + 1);
    memcpy(value, value_start, size);
    value[size] = '\0';
    return value;
}
return NULL;
}

Usage:

char * value = getAttributeValue("atrName", attributes, nb_attributes);
// do your magic
free(value);
Petr
  • 1,159
  • 10
  • 20
0

The easiest way I found using libxml2 (through libxml++ in C++) was to use the eval_to_XXX methods. They evaluate an XPath expression, so you need to use the @property syntax.

For example:

std::string get_property(xmlpp::Node *const &node) {
    return node->eval_to_string("@property")
}
Martín Coll
  • 3,368
  • 3
  • 37
  • 52
  • The more efficient and direct way with libxml++ is `return std::string(dynamic_cast(node)->get_attribute_value("property"))`. Also, your parameter declaration is weird: you declare `node` as a reference to a const pointer to non-const `xmlpp::Node`. More useful would be: `const xmlpp::Node *node` – maxschlepzig Nov 11 '17 at 17:29