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:
parent
44419ec729
commit
d9546b7c2a
|
|
@ -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 许可证)
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue