C语言两个libxml2库使用的问题

摘要:
最近使用libxml2想做点东西,翻看一些example后还是有些疑问,去segmentfault问了下,感谢@pingjiang的热心解答,问题解决,记录如下(一)如下是一个XML文件,p为根结点123我想在根节点之外再添加个标签如下:123(二)还有就是有一个子结构如下123123......向去掉最外层的p标签,而里面的内容保留。

最近使用libxml2想做点东西,翻看一些example后还是有些疑问,去segmentfault问了下,感谢@pingjiang的热心解答,问题解决,记录如下

(一)如下是一个XML文件,p为根结点

<p>
    <one>1</one>
    <two>2</two>
    <three>3</three>
</p>

我想在根节点之外再添加个标签如下:

<main>
    <p>
        <one>1</one>
        <two>2</two>
        <three>3</three>
    </p>
</main>

(二)还有就是有一个子结构如下

<p>
    <a1>
        <one>1</one>
        <two>2</two>
        <three>3</three>
    </a1>
    <a2>
        <one>1</one>
        <two>2</two>
        <three>3</three>
    </a2>
    ......
</p>

向去掉最外层的p标签,而里面的内容保留(我找的示例删除节点,里面的子节点也都没有了)。

完整的实现:

/**
 * section: Tree
 * synopsis: Navigates a tree to print element names
 * purpose: Parse a file to a tree, use xmlDocGetRootElement() to
 *          get the root element, then walk the document and print
 *          all the element name in document order.
 * usage: tree1 filename_or_URL
 * test: tree1 test2.xml > tree1.tmp && diff tree1.tmp $(srcdir)/tree1.res
 * author: Dodji Seketeli
 * copy: see Copyright for the status of this software.
 */
#include <stdio.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

/*
 *To compile this file using gcc you can type
 *  gcc `xml2-config --cflags --libs` -o tree1 tree1.c
 *Run this program
 *  ./tree1 test.xml
 */

static const char* LEVELS[] = {"", " ", "  ", "   ", "    ", "     ", "      ", "       " };

static void printTree(xmlNode * a_node, int level);

/**
 * print_element_names:
 * @a_node: the initial xml node to consider.
 *
 * 打印所有兄弟节点和子节点的名字.
 */
static void print_element_names(xmlNode * a_node, const char* msg);

// 根据标签名称获取节点(可以实现更加复杂的逻辑,获取指定节点)
static xmlNode *getNode(xmlNode *rootNode, const char* tag, xmlNode **parentNode);

// 删除当前节点,但是保留子节点
static void removeNode(xmlNode *parentNode, xmlNode *nodeToDelete);

// 用一个父节点包装子节点
static void wrapWithNode(xmlNode *parentNode, xmlNode *node, xmlNode *newNode);

// 增加一个新节点
static void appendNewChildNode(xmlNode *parentNode, xmlNode *newNode);

/**
 * print_element_names:
 * @a_node: the initial xml node to consider.
 *
 * Prints the names of the all the xml elements
 * that are siblings or children of a given xml node.
 */
static int test_removeNode(const char* filepath);

/**
 * print_element_names:
 * @a_node: the initial xml node to consider.
 *
 * Prints the names of the all the xml elements
 * that are siblings or children of a given xml node.
 */
static int test_wrapWithNode(const char* filepath);

int main(int argc, char **argv)
{
    if (argc != 2) {
        printf("error: invalid arguments");
        return -1;
    }

   /*
    * this initialize the library and check potential ABI mismatches
    * between the version it was compiled for and the actual shared
    * library used.
    */
   LIBXML_TEST_VERSION

    printf("test: removeNode:
");
    test_removeNode(argv[1]);

    printf("

test: wrapWithNode
");
    test_wrapWithNode(argv[1]);

   /*
    *Free the global variables that may
    *have been allocated by the parser.
    */
   xmlCleanupParser();

   return 0;
}

void print_element_names(xmlNode * a_node, const char* msg)
{
    xmlNode *cur_node = NULL;

    if (msg != NULL && strlen(msg) > 0) {
        printf("print: %s
", msg);
    }

    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
        if (cur_node->type == XML_ELEMENT_NODE) {
            printf("node type: Element, name: %s
", cur_node->name);
        }

        print_element_names(cur_node->children, "");
    }
}

void printTree(xmlNode * a_node, int level)
{
    xmlNode *cur_node = NULL;

    //printf("%s", LEVELS[level]);

    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
        if (cur_node->type == XML_ELEMENT_NODE) {
            printf("%s%s <%d>
", LEVELS[level], cur_node->name, cur_node->type);
            printTree(cur_node->children, level + 1);
        } else {
            printf("%s#%s <%d>
", LEVELS[level], cur_node->name, cur_node->type);
        }
    }
}

xmlNode *getNode(xmlNode *rootNode, const char* tag, xmlNode **parentNode) {
    xmlNode *cur = rootNode;
    if ((cur->type == XML_ELEMENT_NODE) && (!xmlStrcmp(cur->name, (const xmlChar *)tag))){
        *parentNode = NULL;
        return cur;
    }

    *parentNode = cur;
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
        if ((cur->type == XML_ELEMENT_NODE) && (!xmlStrcmp(cur->name, (const xmlChar *)tag))){
            return cur;
        }

        if (cur->type == XML_ELEMENT_NODE) {
            *parentNode = cur;
        }
        cur = cur->next;
    }

    return NULL;
}

// 删除当前节点,但是保留子节点
void removeNode(xmlNode *parentNode, xmlNode *nodeToDelete) {
    if (nodeToDelete == NULL) {
        printf("error: nodeToDelete is null");
        return;
    }

    xmlNodePtr siblingNode = nodeToDelete->next;

    while (siblingNode != NULL) {
        if (siblingNode->type == XML_ELEMENT_NODE) {
            printf("debug: found sibling: %s
", siblingNode->name);
            break;
        }

        siblingNode = siblingNode->next;
    }

    printf("debug: parentNode: %s, nodeToDelete: %s
", parentNode->name, nodeToDelete->name);
    printTree(parentNode, 0);

    xmlNode *childrenNode = nodeToDelete->children;
    if (childrenNode == NULL) {
        printf("warn: childrenNode is null
");
    }
    //xmlUnlinkNode(nodeToDelete->children);

    xmlNodePtr nextChildNode = NULL;

    while (childrenNode != NULL) {
        printf("debug: childrenNode: %s
", childrenNode->name);
        nextChildNode = childrenNode->next;
        xmlUnlinkNode(childrenNode);

        if (siblingNode != NULL) {
            printf("debug: addPreSibling: %s, sibling is %s
", childrenNode->name, siblingNode->name);
            xmlAddPrevSibling(siblingNode, nextChildNode);
        } else {
            printf("debug: addChild: %s, parent is %s
", childrenNode->name, parentNode->name);
            printTree(childrenNode, 0);
            xmlAddChild(parentNode, childrenNode);
        }

        childrenNode = nextChildNode;
    }

    xmlUnlinkNode(nodeToDelete);
    xmlFreeNode(nodeToDelete);
}

// 用一个父节点包装子节点
void wrapWithNode(xmlNode *parentNode, xmlNode *node, xmlNode *newNode) {
    xmlUnlinkNode(node);
    xmlAddChild(newNode, node);
    xmlAddChild(parentNode, newNode);
}

// 增加一个新节点
void appendNewChildNode(xmlNode *parentNode, xmlNode *newNode) {
    xmlAddChild(parentNode, newNode);
}

int test_removeNode(const char* filepath) {
    xmlDoc *doc = NULL;
    xmlNode *root_element = NULL;
    xmlNode *parentNode = NULL;
    xmlNode *curNode = NULL;

    /*parse the file and get the DOM */
    doc = xmlReadFile(filepath, NULL, 0);

    if (doc == NULL) {
        printf("error: could not parse file %s
", filepath);
    }

    /*Get the root element node */
    root_element = xmlDocGetRootElement(doc);

    // 删除节点,但是保留子节点
    curNode = getNode(root_element, "p", &parentNode);
    if (curNode == NULL) {
        printf("error: p node is not found");
        return -1;
    }
    if (parentNode == NULL) {
        // 根节点只能有一个子节点,这里就不处理了
        printf("error: This is root node, should treat specially. root node should have only one node");
        return -1;
    }
    removeNode(parentNode, curNode);

    // 重新获取跟节点,应该是main了
    root_element = xmlDocGetRootElement(doc);

    print_element_names(root_element, "after delete");

    /*free the document */
    xmlFreeDoc(doc);
    return 0;
}

int test_wrapWithNode(const char* filepath) {
    xmlDoc *doc = NULL;
    xmlNode *root_element = NULL;
    xmlNode *newNode = NULL;

    /*parse the file and get the DOM */
    doc = xmlReadFile(filepath, NULL, 0);

    if (doc == NULL) {
        printf("error: could not parse file %s
", filepath);
    }

    /*Get the root element node */
    root_element = xmlDocGetRootElement(doc);

    // 增加一个父节点,根节点需要特殊处理
    xmlUnlinkNode(root_element);
    newNode = xmlNewNode(NULL, BAD_CAST "main");
    xmlAddChild(newNode, root_element);
    xmlDocSetRootElement(doc, newNode);
    // 重新获取跟节点,应该是main了
    root_element = xmlDocGetRootElement(doc);

    print_element_names(root_element, "after wrap");

    /*free the document */
    xmlFreeDoc(doc);

    return 0;
}

示例使用的是如下XML文件:

<parent>
	<p>
		<a1>
		    <one>1</one>
		    <two>2</two>
		    <three>3</three>
		</a1>
		<a2>
		    <one>1</one>
		    <two>2</two>
		    <three>3</three>
		</a2>
	</p>
</parent>

结果:

print: after delete **删除节点p后的节点树**
node type: Element, name: parent
node type: Element, name: a1
node type: Element, name: one
node type: Element, name: two
node type: Element, name: three
node type: Element, name: a2
node type: Element, name: one
node type: Element, name: two
node type: Element, name: three

test: wrapWithNode **增加一个main节点后的节点树**
print: after wrap
node type: Element, name: main
node type: Element, name: parent
node type: Element, name: p
node type: Element, name: a1
node type: Element, name: one
node type: Element, name: two
node type: Element, name: three
node type: Element, name: a2
node type: Element, name: one
node type: Element, name: two
node type: Element, name: three

代码还没仔细看,略看下,写的非常不错,真乃大神,看来得细细的啃一下libxml2的源码才行….
想要完成全部的XML处理还需自己多多的了解。

免责声明:文章转载自《C语言两个libxml2库使用的问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇drupal8变量的存储和设定使用yml文件live555 编译下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Oracle 计算工时除去节假日(返回小时数)

--前提条件:DIM_oa_TIME 包含每一天,并且is_work=1 工作日 =0 非工作日 --详见:https://www.cnblogs.com/xiaobaidejiucuoben/p/14630923.html create or replace function getworktime(begindate in date,enddate...

NX二次开发-UFUN获取整形输入值uc1608

#include <uf.h>#include <uf_ui.h> UF_initialize(); char* cp1 = "提示内容"; char cp2[3][16] = {"菜单1", "菜单2", "菜单3"}; int ip3 = 3; int ia4[3] = {5,6,7}; double ra5[3]; int...

智能指针处理---bo

//sdltest1.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h"#include <stdio.h>#include <stdlib.h> extern "C"{ #include <SDL.h>#include "libavutil/opt.h"#include "l...

饿了么vue-cli3.0+cube-ui笔记

1、目录结构 模板文件是public里的index.html,运行项目的时候,会引用src/main.js(入口文件) 详细文档在这里:https://cli.vuejs.org/zh/config/#pwa public:放着html模板和静态资源,public/index.html文件是一个会被html-webpack-plugin处理的模板。在构建...

C# AE 实现点选框选/点击选择要素

选择一个要素或者一个要素集(FeatureSelection)的方法很多,如IMap::SelectByShape、ILayer::search、IFeatureSection::SelectFeature等方法 主要用到的方法 方法一: IMap接口的SelectFeature(Layer, Feature) (方法,从一个Layer中选择一个Featu...

手写Redux-Saga源码

上一篇文章我们分析了Redux-Thunk的源码,可以看到他的代码非常简单,只是让dispatch可以处理函数类型的action,其作者也承认对于复杂场景,Redux-Thunk并不适用,还推荐了Redux-Saga来处理复杂副作用。本文要讲的就是Redux-Saga,这个也是我在实际工作中使用最多的Redux异步解决方案。Redux-Saga比Redux...