POCO 简单写XML文档
参考:https://blog.csdn.net/ma52103231/article/details/7609868
先介绍一下XML文档中有哪些元素:
- Element-文档中某个节点
- Attr-文档中某个节点的属性
- Text-文档中某个节点的文本
- Comment-注释
- ProcessingInstruction-处理信息
对于我们程序员设计网络包来说,前三个够用,起码对我目前来说。既然要用这些属性,那么我们就需要在我们的程序中包含这些头文件:
#include "Poco/DOM/Text.h"
#include "Poco/DOM/Element.h"
#include "Poco/DOM/Comment.h"
#include "Poco/DOM/ProcessingInstruction.h"
#include "Poco/DOM/Attr.h"
除此之外,POCO对文档的抽象类Document也要包含:
#include "Poco/DOM/Document.h"
必要的头文件包含之后,我们就可以动手写一个小程序了:
AutoPtr<Poco::XML::Document> pDoc = new Poco::XML::Document;
AutoPtr<Poco::XML::Element> myRoot = pDoc->createElement("Root");
AutoPtr<Poco::XML::Element> myChild = pDoc->createElement("Child");
AutoPtr<Poco::XML::Element> myGrandChild = pDoc->createElement("GrandChild");
AutoPtr<Poco::XML::Text> nameNode = pDoc->createTextNode("my_name_is_xiaoqiang");
AutoPtr<Poco::XML::ProcessingInstruction> pi = pDoc->createProcessingInstruction("xml","version='1.0' encoding='UTF-8'" );
AutoPtr<Poco::XML::Comment> comm = pDoc->createComment("new_day");
为什么 Document
前面会有 Poco::XML::
这个东西?此东西为命名空间,POCO库中有很多命名空间,分门别类,很是醒目,所以你需要如此做。或者,你可以像 using namespace std;
一样在函数前面写上:
using Poco::XML::Document;
其他的类似。而 AutoPtr
是个智能指针类,它负责在指明的对象不用时帮你析构了,这个在POCO库中经常用到,要非常小心。
上面这些代码的作用是创建是元素,下面让我们来把他们组合成一个文档:
myGrandChild->appendChild(nameNode);
myChild->appendChild(myGrandChild);
myRoot->appendChild(myChild);
pDoc->appendChild(pi);
pDoc->appendChild(comm);
pDoc->appendChild(myRoot);
组合成文档之后,我们需要将这个文档直接写入目标文件:
DOMWriter write;
write.setOptions(XMLWriter::PRETTY_PRINT);
FileStream ofs("./example.txt",std::ios::in);
write.writeNode(ofs,pDoc);
第一句代码是创建一个写的人,他负责将文档写入文件。
第二句代码是每一个元素都在文件中另起一行,易于读者观看。
第三句代码创建一个POCO的文件流,指定目标文件和动作。
第四句代码,将数据通过流写入到文件中。
编译过程中会出错,因为DOMWriter,FileStream的头文件还没有包含呢,所以需要再包含这两个头文件。
POCO 简单读XML文档
参考:https://blog.csdn.net/ma52103231/article/details/7701880
Poco中XML各元素被抽象成的关系:
可以看到,任何元素都被抽象成Node,同时又分为类型的节点。(Attr和Notation看成一种)
- CharacterData,这类Node是Name不可变,而Value可以由用户自定义。
- AbstractContainerNode,这类Node有个特点,即含有属性,特别的对于Element节点,Name可以由用户自定义,而Value不可变。
- 右边两个,它们既可以改变Name,也可以改变Value。
每个Element后面跟的#text内容是 \n\t(\t的个数根据文档的格式)
xml与kv相互转化
github:https://github.com/Angelia-Wang/poco_xml_to_kv
实现ClickHouse的xml配置文件的poco::xml::document对象与kv对象的相互转化。
对kv的定义:
class Item {
public:
Item(std::string _name) : name(_name) {}
Item() {}
std::map<std::string, std::string> attr; // 参数的属性
std::string name; // 配置的参数名
std::string value; // 参数值
};
xml文件示例:
<clickhouse>
<listen_host>0.0.0.0</listen_host>
<listen_host>localhost</listen_host>
<global_config>uncompressed_cache_size,remote_servers.shard_0.shard[0]</global_config>
<logger>
<level>trace</level>
<log>/root/chdata/log/clickhouse-server/clickhouse-server.log</log>
<size>100M</size>
</logger>
<uncompressed_cache_size>8589934592</uncompressed_cache_size>
<mark_cache_size>5368709120</mark_cache_size>
<mlock_executable>true</mlock_executable>
<remote_servers>
<shard_0>
<shard c1="5">
<replica>
<host a1="1" a2="2">clickhouse-env-dev-ch</host>
<port>9000</port>
</replica>
<replica>
<host a3="3" a4="4">clickhouse-env-dev-ch2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host b1="1" b2="2">clickhouse-env-runner-0.clickhouse-env-runner</host>
<port>9000</port>
</replica>
<replica>
<host b3="3" b4="4">clickhouse-env-runner-0.clickhouse-env-runner2</host>
<port>9000</port>
</replica>
</shard>
</shard_0>
<shard_1>
<shard>
<replica>
<host>clickhouse-env-runner-0.clickhouse-env-runner</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse-env-runner-1.clickhouse-env-runner</host>
<port>9000</port>
</replica>
</shard>
</shard_1>
</remote_servers>
</clickhouse>
示例转成的kv对象:
name:value
attr_name:attr_value
listen_host[0]:0.0.0.0
listen_host[1]:localhost
global_config:uncompressed_cache_size,remote_servers.shard_0.shard[0]
logger.level:trace
logger.log:/root/chdata/log/clickhouse-server/clickhouse-server.log
logger.size:100M
uncompressed_cache_size:8589934592
mark_cache_size:5368709120
mlock_executable:true
remote_servers.shard_0.shard[0]:
c1:5
remote_servers.shard_0.shard[0].replica[0].host:clickhouse-env-dev-ch
a1:1
a2:2
remote_servers.shard_0.shard[0].replica[0].port:9000
remote_servers.shard_0.shard[0].replica[1].host:clickhouse-env-dev-ch2
a3:3
a4:4
remote_servers.shard_0.shard[0].replica[1].port:9000
remote_servers.shard_0.shard[1].replica[0].host:clickhouse-env-runner-0.clickhouse-env-runner
b1:1
b2:2
remote_servers.shard_0.shard[1].replica[0].port:9000
remote_servers.shard_0.shard[1].replica[1].host:clickhouse-env-runner-0.clickhouse-env-runner2
b3:3
b4:4
remote_servers.shard_0.shard[1].replica[1].port:9000
remote_servers.shard_1.shard[0].replica.host:clickhouse-env-runner-0.clickhouse-env-runner
remote_servers.shard_1.shard[0].replica.port:9000
remote_servers.shard_1.shard[1].replica.host:clickhouse-env-runner-1.clickhouse-env-runner
remote_servers.shard_1.shard[1].replica.port:9000
此处kv对象的name符合 Poco/Util/XMLConfiguration.h 中对name的格式,通过 has
方法能判断name对应的参数在xml文件中是否存在。
using ConfigurationPtr = Poco::AutoPtr<Poco::Util::AbstractConfiguration>;
if (configuration->has(name)){
...
}
通过Poco::XML::Document的 getNodeByPath
方法,能得到 Document 对象中对应 path 的 Node 结点。
name 和 path 对应关系举例:
- name = remote_servers.shard_1.shard[0].replica.host
- path = remote_servers/shard_1/shard[0]/replica/host