feat(libxml): add XML parsing library with C API wrapping tinyxml2

- 纯 C 接口(myXml.h)包装 tinyxml2 C++ 实现
- 14 个 API:文档加载/创建/释放、元素遍历、属性读写
- 不透明句柄 myXmlDoc_t / myXmlElem_t
- x86 编译通过,产物 libxml.a
This commit is contained in:
ypc 2026-07-07 17:29:31 +08:00
parent 44419ec729
commit d9546b7c2a
7 changed files with 5797 additions and 0 deletions

View File

@ -0,0 +1,24 @@
# API-libxml — XML 解析模块
> C 接口包装 tinyxml2供 libdatacenter 等模块调用。
## 接口
| 函数 | 说明 |
|------|------|
| `myXml_load_file(path)` | 从文件加载 XML返回不透明文档句柄 |
| `myXml_new_doc(root_name)` | 新建空 XML 文档 |
| `myXml_free_doc(doc)` | 释放文档 |
| `myXml_root_elem(doc)` | 获取根元素 |
| `myXml_save_file(doc, path)` | 保存到文件 |
| `myXml_first_child(parent, name)` | 查找第一个匹配子元素 |
| `myXml_next_sibling(elem, name)` | 查找下一个匹配兄弟元素 |
| `myXml_attr_str(elem, name, def)` | 获取字符串属性 |
| `myXml_attr_float(elem, name, def)` | 获取 float 属性 |
| `myXml_attr_int(elem, name, def)` | 获取 int 属性 |
| `myXml_new_child(parent, name)` | 创建子元素 |
| `myXml_set_attr/set_attr_int/set_attr_float` | 设置属性 |
## 依赖
- `tinyxml2`内置源码Zlib 许可证)

72
release/inc/myXml.h Normal file
View File

@ -0,0 +1,72 @@
/**
* @file myXml.h
* @brief XML C tinyxml2
* @details C XML DOM
* C++ tinyxml2 C
*/
#ifndef _MY_XML_H_
#define _MY_XML_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* 不透明句柄 */
typedef void *myXmlDoc_t;
typedef void *myXmlElem_t;
/* ========== 文档生命周期 ========== */
/** 从文件加载 XML 文档,失败返回 NULL */
myXmlDoc_t myXml_load_file(const char *path);
/** 新建空 XML 文档(含 XML 声明) */
myXmlDoc_t myXml_new_doc(const char *root_name);
/** 释放文档 */
void myXml_free_doc(myXmlDoc_t doc);
/** 获取根元素 */
myXmlElem_t myXml_root_elem(myXmlDoc_t doc);
/** 保存文档到文件 */
int myXml_save_file(myXmlDoc_t doc, const char *path);
/* ========== 元素查询 ========== */
/** 查找第一个匹配名称的子元素 */
myXmlElem_t myXml_first_child(myXmlElem_t parent, const char *name);
/** 查找下一个匹配名称的兄弟元素 */
myXmlElem_t myXml_next_sibling(myXmlElem_t elem, const char *name);
/** 获取字符串属性,不存在返回默认值 */
const char *myXml_attr_str(myXmlElem_t elem, const char *name, const char *def_val);
/** 获取 float 属性,不存在返回默认值 */
float myXml_attr_float(myXmlElem_t elem, const char *name, float def_val);
/** 获取 int 属性,不存在返回默认值 */
int myXml_attr_int(myXmlElem_t elem, const char *name, int def_val);
/* ========== 元素创建 ========== */
/** 为父节点创建子元素 */
myXmlElem_t myXml_new_child(myXmlElem_t parent, const char *name);
/** 设置字符串属性 */
void myXml_set_attr(myXmlElem_t elem, const char *name, const char *value);
/** 设置 int 属性 */
void myXml_set_attr_int(myXmlElem_t elem, const char *name, int value);
/** 设置 float 属性 */
void myXml_set_attr_float(myXmlElem_t elem, const char *name, float value);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,32 @@
include ./../../../linux.mk
L := $(notdir $(realpath $(CURDIR)/..))
M := libxml
O := $(LIB_REL)/$(M).a
S := $(SRC_ROOT_DIR)/$(L)/libxml/src
I := -I$(SRC_ROOT_DIR)/$(L)/libxml/inc
B := $(CURDIR)/$(M)/obj
SRCS := $(wildcard $(S)/*.cpp)
OBJS := $(patsubst $(S)/%.cpp, $(B)/%.o, $(SRCS))
F := $(CXX_FLAGS) $(I)
.PHONY: all
all:
@mkdir -p $(ROOT_DIR)/release/inc
@cp -f $(S:src=inc)/*.h $(ROOT_DIR)/release/inc/ 2>/dev/null; true
@$(MAKE) $(O)
$(O): $(OBJS)
@mkdir -p $(dir $@)
$(AR) rcs $@ $^
@echo "[$(M)] built"
$(B)/%.o: $(S)/%.cpp
@mkdir -p $(dir $@)
$(CXX) $(F) -c $< -o $@
.PHONY: clean
clean:
rm -rf $(B) $(O)
.PHONY: rebuild
rebuild: clean all

View File

@ -0,0 +1,72 @@
/**
* @file myXml.h
* @brief XML C tinyxml2
* @details C XML DOM
* C++ tinyxml2 C
*/
#ifndef _MY_XML_H_
#define _MY_XML_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* 不透明句柄 */
typedef void *myXmlDoc_t;
typedef void *myXmlElem_t;
/* ========== 文档生命周期 ========== */
/** 从文件加载 XML 文档,失败返回 NULL */
myXmlDoc_t myXml_load_file(const char *path);
/** 新建空 XML 文档(含 XML 声明) */
myXmlDoc_t myXml_new_doc(const char *root_name);
/** 释放文档 */
void myXml_free_doc(myXmlDoc_t doc);
/** 获取根元素 */
myXmlElem_t myXml_root_elem(myXmlDoc_t doc);
/** 保存文档到文件 */
int myXml_save_file(myXmlDoc_t doc, const char *path);
/* ========== 元素查询 ========== */
/** 查找第一个匹配名称的子元素 */
myXmlElem_t myXml_first_child(myXmlElem_t parent, const char *name);
/** 查找下一个匹配名称的兄弟元素 */
myXmlElem_t myXml_next_sibling(myXmlElem_t elem, const char *name);
/** 获取字符串属性,不存在返回默认值 */
const char *myXml_attr_str(myXmlElem_t elem, const char *name, const char *def_val);
/** 获取 float 属性,不存在返回默认值 */
float myXml_attr_float(myXmlElem_t elem, const char *name, float def_val);
/** 获取 int 属性,不存在返回默认值 */
int myXml_attr_int(myXmlElem_t elem, const char *name, int def_val);
/* ========== 元素创建 ========== */
/** 为父节点创建子元素 */
myXmlElem_t myXml_new_child(myXmlElem_t parent, const char *name);
/** 设置字符串属性 */
void myXml_set_attr(myXmlElem_t elem, const char *name, const char *value);
/** 设置 int 属性 */
void myXml_set_attr_int(myXmlElem_t elem, const char *name, int value);
/** 设置 float 属性 */
void myXml_set_attr_float(myXmlElem_t elem, const char *name, float value);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
/**
* @file myXml.cpp
* @brief XML C tinyxml2
*/
#include "myXml.h"
#include "tinyxml2.h"
extern "C"
{
myXmlDoc_t myXml_load_file(const char *path)
{
if (!path)
{
return NULL;
}
tinyxml2::XMLDocument *doc = new tinyxml2::XMLDocument();
if (doc->LoadFile(path) != tinyxml2::XML_SUCCESS)
{
delete doc;
return NULL;
}
return (myXmlDoc_t)doc;
}
myXmlDoc_t myXml_new_doc(const char *root_name)
{
tinyxml2::XMLDocument *doc = new tinyxml2::XMLDocument();
doc->InsertEndChild(doc->NewDeclaration());
if (root_name)
{
doc->InsertEndChild(doc->NewElement(root_name));
}
return (myXmlDoc_t)doc;
}
void myXml_free_doc(myXmlDoc_t doc)
{
if (doc)
{
delete (tinyxml2::XMLDocument *)doc;
}
}
myXmlElem_t myXml_root_elem(myXmlDoc_t doc)
{
if (!doc)
{
return NULL;
}
return (myXmlElem_t)(((tinyxml2::XMLDocument *)doc)->RootElement());
}
int myXml_save_file(myXmlDoc_t doc, const char *path)
{
if (!doc || !path)
{
return -1;
}
tinyxml2::XMLDocument *pdoc = (tinyxml2::XMLDocument *)doc;
return (pdoc->SaveFile(path) == tinyxml2::XML_SUCCESS) ? 0 : -1;
}
myXmlElem_t myXml_first_child(myXmlElem_t parent, const char *name)
{
if (!parent || !name)
{
return NULL;
}
return (myXmlElem_t)(((tinyxml2::XMLElement *)parent)->FirstChildElement(name));
}
myXmlElem_t myXml_next_sibling(myXmlElem_t elem, const char *name)
{
if (!elem || !name)
{
return NULL;
}
return (myXmlElem_t)(((tinyxml2::XMLElement *)elem)->NextSiblingElement(name));
}
const char *myXml_attr_str(myXmlElem_t elem, const char *name, const char *def_val)
{
if (!elem || !name)
{
return def_val;
}
const char *val = ((tinyxml2::XMLElement *)elem)->Attribute(name);
return val ? val : def_val;
}
float myXml_attr_float(myXmlElem_t elem, const char *name, float def_val)
{
if (!elem || !name)
{
return def_val;
}
return ((tinyxml2::XMLElement *)elem)->FloatAttribute(name, def_val);
}
int myXml_attr_int(myXmlElem_t elem, const char *name, int def_val)
{
if (!elem || !name)
{
return def_val;
}
return ((tinyxml2::XMLElement *)elem)->IntAttribute(name, def_val);
}
myXmlElem_t myXml_new_child(myXmlElem_t parent, const char *name)
{
if (!parent || !name)
{
return NULL;
}
tinyxml2::XMLDocument *doc = ((tinyxml2::XMLElement *)parent)->GetDocument();
return (myXmlElem_t)(doc->NewElement(name));
}
void myXml_set_attr(myXmlElem_t elem, const char *name, const char *value)
{
if (!elem || !name || !value)
{
return;
}
((tinyxml2::XMLElement *)elem)->SetAttribute(name, value);
}
void myXml_set_attr_int(myXmlElem_t elem, const char *name, int value)
{
if (!elem || !name)
{
return;
}
((tinyxml2::XMLElement *)elem)->SetAttribute(name, value);
}
void myXml_set_attr_float(myXmlElem_t elem, const char *name, float value)
{
if (!elem || !name)
{
return;
}
((tinyxml2::XMLElement *)elem)->SetAttribute(name, value);
}
} /* extern "C" */

File diff suppressed because it is too large Load Diff