传递Pointers指针使用libxml2搜索xmlTree

时间:2013-11-06 00:11:17

标签: c xml pointers libxml2

所以我需要和xml文档一起搜索特定的标签。我使用的是libxml2,我有一个函数,它将递归搜索具有指定名称的节点并输出它们的数量。但是当我传递相同的函数时,一个数组来填充一些奇怪的东西,基本上我认为我应该传递一个三指针,但一切似乎都没有正常工作正在发生在我传递函数的内存地址。我是初学者,虽然我对指针有很好的处理但我认为typedef和多个指针层让我搞砸了。在发布之前,我确实看过很多帖子。代码在我的机器上编译,但是当我打印收集的节点的名称时,我得到一个seg错误。

#include <stdio.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

int FindNodesByTagName(xmlNodePtr *ptr_array[], xmlNodePtr a_node, char tagname[]);

int main(void)
{

    int num_chan, k;
    xmlDocPtr doc;
    xmlNodePtr cur;
    xmlNodePtr *x;


char xstr[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                "<chan>"
                "<blah>"
                    "<wrong>"
                        "<other>"
                            "<ele>some_text</ele>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                        "</other>"
                    "</wrong>"
                "</blah>"
                "<blah>"
                    "<foo>"
                        "<enabled>true</enabled>"
                    "</foo>"
                    "<foo>"
                        "<enabled>false</enabled>"
                    "</foo>"
                "</blah>"
                "<enabled>false</enabled>"
                "<enabled>true</enabled>"
                "</chan>";

    doc = xmlParseMemory(xstr, sizeof(xstr) / sizeof(*xstr) );

    cur = xmlDocGetRootElement(doc);

    num_chan = FindNodesByTagName(NULL, cur, "enabled");

    x = calloc(sizeof(xmlNodePtr), num_chan);

    FindNodesByTagName(&x, cur, "enabled");

    for(k=0; k < num_chan; k++)
        printf("%s\n", x[k]->name);

    printf("%i\n", num_chan);
    free(x);
    return 0;
}

int FindNodesByTagName(xmlNodePtr *ptr_array[], xmlNodePtr a_node, char tagname[]){

    int counter = 0;
    xmlNode *cur_node = NULL;
    int isElementNode;
    int isTagName;

    for (cur_node = a_node; cur_node; cur_node = cur_node->next){
        isElementNode = (cur_node->type == XML_ELEMENT_NODE);
        isTagName = !xmlStrcmp(cur_node->name, (const xmlChar *) tagname);
        if (isElementNode & isTagName){
            counter ++;
            if (ptr_array != NULL) {
                **ptr_array = cur_node;
                /*printf("P2P %p, CA %p, DR %p, V %p\n", ptr_array, *ptr_array, **ptr_array, cur_node);*/
                (*ptr_array)++;
            }

        }
        counter += FindNodesByTagName(ptr_array, cur_node->children, tagname);
    }

    return counter;
}

3 个答案:

答案 0 :(得分:1)

让它运行的变化:

int FindNodesByTagName(xmlNodePtr *ptr_array[], xmlNodePtr a_node, char tagname[]);
// becomes
int FindNodesByTagName(xmlNodePtr ptr_array[], xmlNodePtr a_node, char tagname[]);

FindNodesByTagName(&x, cur, "enabled");
// becomes
FindNodesByTagName(x, cur, "enabled");

int FindNodesByTagName(xmlNodePtr *ptr_array[], xmlNodePtr a_node, char tagname[]){
// becomes
int FindNodesByTagName(xmlNodePtr ptr_array[], xmlNodePtr a_node, char tagname[]){

**ptr_array = cur_node;
// becomes
*ptr_array = cur_node;

(*ptr_array)++;
// becomes
ptr_array++;

我发现xmlNodePtrxmlNode *令人憎恶的伪装。我做的第一件事就是将所有xmlNodePtr转换为xmlNode *

观察这些变化,我责怪xmlNodePtr大部分的混乱。无论如何,请记住void foo(int bar[])之类的内容与void foo(int * bar)相同。希望你能从差错中看出你出错了。

答案 1 :(得分:0)

所以下面的代码工作我仍然无法安静地围绕我为什么我不能通过传递函数FindNodesByTagName&amp; x。我知道它与传递引用和传递值有关,事实上我在函数中操作该值,但我仍然无法将它全部安静地解决。目前我正在向前迈进,我必须分配给另一个变量,然后将指针传递给另一个变量。

#include <stdio.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

int FindNodesByTagName(xmlNodePtr *ptr_array[], xmlNodePtr a_node, char tagname[]);

int main(void)
{

    int num_chan, k;
    xmlDocPtr doc;
    xmlNodePtr cur;
    xmlNode **x, **t;


    char xstr[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                "<chan>"
                "<blah>"
                    "<wrong>"
                        "<other>"
                            "<ele>some_text</ele>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                        "</other>"
                    "</wrong>"
                "</blah>"
                "<blah>"
                    "<foo>"
                        "<enabled>true</enabled>"
                    "</foo>"
                    "<foo>"
                        "<enabled>false</enabled>"
                    "</foo>"
                "</blah>"
                "<enabled>false</enabled>"
                "<enabled>true</enabled>"
                "</chan>";

    doc = xmlParseMemory(xstr, sizeof(xstr) / sizeof(*xstr) );

    cur = xmlDocGetRootElement(doc);

    num_chan = FindNodesByTagName(NULL, cur, "enabled");

    x = calloc(sizeof(xmlNode *), num_chan);

    t = x;

    FindNodesByTagName(&t, cur, "enabled");

    for(k=0; k < num_chan; k++)
        printf("%s\n", x[k]->name);

    printf("%i\n", num_chan);
    free(x);
    return 0;
}

int FindNodesByTagName(xmlNode ***ptr_array, xmlNodePtr a_node, char tagname[]){

    int counter = 0;
    xmlNode *cur_node = NULL;
    int isElementNode;
    int isTagName;

    for (cur_node = a_node; cur_node; cur_node = cur_node->next){
        isElementNode = (cur_node->type == XML_ELEMENT_NODE);
        isTagName = !xmlStrcmp(cur_node->name, (const xmlChar *) tagname);
        if (isElementNode & isTagName){
            counter ++;
            if (ptr_array != NULL) {
                **ptr_array = cur_node;
                printf("P2P %p, CA %p, DR %p, V %p\n", ptr_array, *ptr_array, **ptr_array, cur_node);
                (*ptr_array)++;
            }

        }
        counter += FindNodesByTagName(ptr_array, cur_node->children, tagname);
    }

    return counter;
}

答案 2 :(得分:0)

所以我现在有一个不同的解决方案。我还是不喜欢它。它基本上还有两个步骤,在我看来应该有一种方法可以一体化。在这个版本中,FindNodesByTagName本质上是一个包装器,因此我可以指向当前数组地址的指针。对于这个包装器,我还更改了函数的签名,以便用户可以直接将指针传递给已分配的数组,我认为这更直观。

#include <stdio.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

int FindNodesByTagName(xmlNode *ptr_array[], xmlNode *a_node, char tagname[]);
int search_tag(xmlNode ***ptr_array, xmlNode *a_node, char tagname[]);

int main(void)
{

    int num_chan, k;
    xmlDocPtr doc;
    xmlNodePtr cur;
    xmlNode **x;

    char xstr[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                "<chan>"
                "<blah>"
                    "<wrong>"
                        "<other>"
                            "<ele>some_text</ele>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                            "<foo>"
                                "<enabled>true</enabled>"
                            "</foo>"
                        "</other>"
                    "</wrong>"
                "</blah>"
                "<blah>"
                    "<foo>"
                        "<enabled>true</enabled>"
                    "</foo>"
                    "<foo>"
                        "<enabled>false</enabled>"
                    "</foo>"
                "</blah>"
                "<enabled>false</enabled>"
                "<enabled>true</enabled>"
                "</chan>";

    /*
     * Parse string and get root element
     */
    doc = xmlParseMemory(xstr, sizeof(xstr) / sizeof(*xstr) );
    cur = xmlDocGetRootElement(doc);

    /*
     * Find number of elements with particular tag name and allocate memory
     * then print out some debug info about them.
     */
    num_chan = FindNodesByTagName(NULL, cur, "enabled");
    x = calloc(sizeof(xmlNode *), num_chan);

    printf("\nAllocated memory before FindNodes\n");
    for(k=0; k < num_chan; k++)
        printf("%i-%p-%p\n", k, x+k, x[k]);

    /*
     * Call FindNodes again this time passing the allocated array to be
     * filled and then print some more debug info to confirm the array was
     * filled correctly.
     */
    FindNodesByTagName(x, cur, "enabled");

    printf("\nAfter FindNodes\n");
    for(k=0; k < num_chan; k++)
        printf("%i-%p-%s\n", k, x[k], x[k]->name);

    free(x);
    return 0;
}

int FindNodesByTagName(xmlNode *ptr_array[], xmlNode *a_node, char tagname[]) {
    /*
     * This function is now essentially just a wrapper and search_tag is
     * doing all the real work.
     */
    int counter;
    xmlNode ***ptr = NULL;

    if (ptr_array)
        ptr = &ptr_array;
    counter = search_tag(ptr, a_node, tagname);

    return counter;
}


int search_tag(xmlNode ***cur_idx, xmlNode *a_node, char tagname[]) {

    int counter = 0;
    int isElementNode;
    int isTagName;
    xmlNode *cur_node = NULL;

     for (cur_node = a_node; cur_node; cur_node = cur_node->next){
        isElementNode = (cur_node->type == XML_ELEMENT_NODE);
        isTagName = !xmlStrcmp(cur_node->name, (const xmlChar *) tagname);
        if (isElementNode & isTagName){
            counter ++;
            if (cur_idx != NULL) {
                **cur_idx = cur_node;
                (*cur_idx)++;
            }
        }
        counter += search_tag(cur_idx, cur_node->children, tagname);
     }
     return counter;
}

代码使用以下命令为我编译

gcc `xml2-config --cflags` name_of_file.c `xml2-config --libs`
相关问题