0

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

#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;
}
4

3 回答 3

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 *可憎的伪装。我为解决此问题所做的第一件事是将全部转换xmlNodePtrxmlNode *.

看着这些变化,我把xmlNodePtr大部分的困惑归咎于。无论如何,请记住,在类似的东西void foo(int bar[])中是一样的void foo(int * bar)。希望你能从差异中看到你出错的地方。

于 2013-11-06T01:29:11.347 回答
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`
于 2014-01-23T13:45:20.480 回答
0

所以下面的代码有效,我仍然不能安静地思考为什么我不能通过函数 FindNodesByTagName &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;
}
于 2013-11-09T17:51:53.930 回答