博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
xml_editor
阅读量:5910 次
发布时间:2019-06-19

本文共 11188 字,大约阅读时间需要 37 分钟。

概要

      该工程是用来操作xml, 目的是为了在程序中操作xml中各类节点更加简单, 下面按照 工程简介, 库内部实现, 库接口使用, xml工具使用, xpath简介 几个部分来介绍该c++库.

工程简介

      我们当前使用的xml解析库, 比如 tinyxml, cmarkup, XmlReader, boost 的 property tree, 其中 tinyxml, cmarkup 能够按照tree方式解析进行解析, XmlReader 针对我们项目对有限制层次的节点属性进行读取, property tree 提供类似文件路径格式的查找, 但功能不够简单, 所以目前的 xml 库或者工具不能很好的满足我们当前的项目需求.

     xpath 是W3C定义的标准的xml 节点路径规范, 通过 xpath 可以对xml中的各类节点进行简单, 快速的定位, 而当前的 libxml2.so 可以很好的支持 xpath 语言. 
     XmlEditor对 libxml2.so 进行了封装, 利用了其中的xpath功能来满足我们的需求.
     注意: 当前只支持 属性节点, 元素节点 , 其他节点暂时不支持.

    工程编译后输出:

  • 动态库:   libxml_editor.so             //对外使用的修改库
  • 工具:      xmleditor                         //基于该库提供的xml节点修改工具
  • 测试用例:xml_editor_test            //库测试用例 

库内部实现

库接口使用

库接口导入项

  • 头文件:     xml_editor.h, xml_editor_exception.h, xml_editor_common.h 
  • 命名空间:  xmleditor, xmleditor::common;
  • 动态库:     libxml_editor.so

库接口使用demo

不熟悉xml基础的看以先看一下这里: xml , ,  (外网)

example.xml
<?
xml
version
=
"1.0"
?>
<
configure
>
    
<
basic
>
        
<
log
dir
=
"./log/"
schedule
=
"hourly"
max_file_index
=
"1000"
/>
        
<
xml
dir
=
"../xml/"
/>
        
<
taskpath
dir
=
"../"
/>
        
<
status
interval
=
"2"
/>
        
<
probe
id
=
"2"
/>
    
</
basic
>
    <
field
id
=
"1"
name
=
"report_sec"
tag
=
"kreport_sec"
type
=
"60"
/>
<!--from Deliver-->  
 
    
<
data
count
=
"5"
>
        
<!--tag  参照total_fields.h-->
        
<
field
id
=
"1"
name
=
"report_sec"
tag
=
"kreport_sec"
type
=
"60"
/>
<!--from Deliver-->
        
<
field
id
=
"2"
name
=
"start_time"
tag
=
"kstart_time"
type
=
"40"
/>
        
<
field
id
=
"3"
name
=
"tp_oa"
tag
=
"ktp_origin_address"
type
=
"30"
> 717171</
field
>
        
<
field
id
=
"4"
name
=
"response_time"
tag
=
"kresponse_time"
type
=
"40"
/>
        
<
field
id
=
"5"
name
=
"up_retrans_pkts"
tag
=
"kup_retrans_pkts"
type
=
"12"
/>
    
</
data
>
</
configure
>
test.cpp
#include <iostream>
#include "xml_editor.h"
 
using
std::cout;
using
std::endl;
using
namespace
xmleditor;
using
namespace
xmleditor::common;
 
void
PrintElement(
const
string& xp,
const
string& element,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute)
{
    
if
(type == XmlNodeType::kXmlNodeTypeAttribute) {
        
cout <<
"Attrbute:  "
<< xp <<
" = \""
<< element <<
"\""
<< endl;
    
}
else
if
(type == XmlNodeType::kXmlNodeTypeElement) {
        
cout <<
"Element:  "
<< xp <<
" = \""
<< element <<
"\""
<< endl;
    
}
else
{
        
cout <<
"Other:  "
<< xp <<
" = \""
<< element <<
"\""
<< endl;
    
}
}
 
int
main()
{
    
try
{
        
string element, xp;
        
XmlEditor editor(
"./example.xml"
);
 
        
//获取 log 的 dir 属性
        
xp =
"/configure/basic/log/@dir"
;
        
editor.GetElement(xp, element);
        
PrintElement(xp, element);
 
        
//获取 第一个field 的 所有属性
        
xp =
"/configure/data/field[1]/@*"
;
        
editor.GetElement(xp, element);
        
PrintElement(xp, element);
 
        
//获取 field id="1" 的 name 属性
        
xp =
"/configure/data/field[@id=1]/@name"
;
        
editor.GetElement(xp, element);
        
PrintElement(xp, element);
 
        
//获取 field id="5"且 name="up_retrans_pkts"的type属性
        
xp =
"/configure/data/field[@id=5][@name=\"up_retrans_pkts\"]/@type"
;
        
editor.GetElement(xp, element);
        
PrintElement(xp, element);
 
        
//获取 field 中的所有name属性
        
xp =
"/configure/data/field/@name"
;
        
editor.GetElement(xp, element);
        
PrintElement(xp, element);
 
        
//修改 log 的 dir 属性
        
xp =
"/configure/basic/log"
;
        
element =
"dir=/opt/omatrix"
;          
//如果写成 dir=\"/opt/omatrix\" 会失败
        
editor.ModElement(xp, element);
        
editor.SaveFile(
""
);
 
        
//增加 log 的属性
        
xp =
"/configure/basic/log"
;
        
element =
"data=2014"
;
        
editor.AddElement(xp, element);
        
editor.SaveFile();
 
        
//删除 log 的属性
        
xp =
"/configure/basic/log"
;
        
element =
"dir=/opt/omatrix"
;
        
editor.DelElement(xp, element);
        
editor.SaveFile();
 
    
}
catch
(XmlEditorException& e) {
        
cout << e.what() << endl;
        
return
-1;
    
}
    
return
0;
}

库接口分类

分为3类: xml 操作, 节点操作, xpath原始运算 

1. xml 操作 

 加载, 卸载, 保存xml

xml 操作
XmlEditor();
XmlEditor(
const
string& xml_name);           
//构造时加载xml
~XmlEditor();
void
LoadFile(
const
string& xml_name);       
//加载xml
void
UnLoadFile();                           
//卸载xml
void
SaveFile(
const
string& xml_name =
""
);  
//保存xml

2. 节点操作

增,删,改,查 xml node, 同一个接口, 对于不同的 node type 含义不同

接口中的公共参数:

  • const string& xpath:             xml中的节点的 xpath 路径 
  • const XmlNodeType type:    当前操作的xml中的节点类型, 默认是 属性节点

      其余参数根据不同的操作和节点类型含义不同, 详细请看下列描述

  1)增加
void
AddElement(
const
string& xpath,
const
std::string& element,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

  如果是属性node    表示给当前的node增一个属性, 

                             Element 需要增加的属性对, 属性和值之间用'='分隔, eg."k=v"

  如果是元素node    表示给当前的node增加一个child node

                             Element 需要增加的node, node name 和node content之间用'='分隔,其中node content可以忽略 eg."n=c"

void
AddElement(
const
string& xpath,
const
std::vector<std::string>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node增一组属性

                            Elements 需要增加的多个属性对, 每个string表示一个属性对, 属性和值之间用'='分隔, eg."k=v"

 如果是元素node  表示给当前的node一组child node

                           Elements  需要增加的node, node name 和node content之间用'='分隔,其中node content可以忽略 eg."n=c"

void
AddElement(
const
string& xpath,
const
std::vector<std::pair<std::string, std::string>>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node增加一组属性

                            Elements 需要增加的多个属性对, 每个pair表示一个属性对, pair.first 表示属性, pair.second 表示属性值

 如果是元素node  表示给当前的node增加一组child node

                           Elements  需要增加的多个node, 每个pair表示一个node, pair.first 表示node name, pair.second 表示node content, pair.second可以为空

  2)删除
void
DelElement(
const
string& path,
const
std::string& element,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

  如果是属性node    表示给当前的node删除一个属性, 

                             Element 需要删除的属性对, 属性和值之间用'='分隔, eg."k=v"

  如果是元素node    表示删除当前的node

                             Element NOUSE

void
DelElement(
const
string& xpath,
const
std::vector<std::string>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node增加一组属性

                            Elements 需要删除的属性对, 每个string表示一个属性对, 属性和值之间用'='分隔, eg."k=v"

 如果是元素node  Undefined                           

void
DelElement(
const
string& xpath,
const
std::vector<std::pair<std::string, std::string>>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node增加一组属性

                            Elements 需删除的多个属性对, 每个pair表示一个属性对, pair.first 表示属性, pair.second 表示属性值

 如果是元素node  Undefined                           

  3)修改
void
ModElement(
const
string& path,
const
std::string& element,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

  如果是属性node    表示给当前的node修改一个属性 

                             Element 需要修改的属性对, 属性和值之间用'='分隔, eg."k=v"

  如果是元素node    表示当前node的text

                             Element NOUSE

void
ModElement(
const
string& xpath,
const
std::vector<std::string>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node修改一组属性

                            Elements 需要修改的属性对, 每个string表示一个属性对, 属性和值之间用'='分隔, eg."k=v"

 如果是元素node   Undefined

void
ModElement(
const
string& xpath,
const
std::vector<std::pair<std::string, std::string>>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示给当前的node修改一组属性

                            Elements 需要修改的多个属性对, 每个pair表示一个属性对, pair.first 表示属性, pair.second 表示属性值

 如果是元素node   Undefined

  4)查找
void
GetElement(
const
string& path, std::string& element,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

  如果是属性node    表示获取一个属性的值

                             Element 输出用, 存放当前一个目标属性的值, eg."v"

  如果是元素node    表示当前node的text

                             Element 输出用, 存放当前node的text

void
GetElement(
const
string& xpath, std::vector<std::string>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示获取一组属性的值

                            Elements 输出用, 存放当前一组目标属性值, 每个string表示一个属性值,eg."v"

 如果是元素node  Undefined

void
GetElement(
const
string& xpath, std::vector<std::pair<std::string, std::string>>& elements,
const
XmlNodeType type = XmlNodeType::kXmlNodeTypeAttribute);

 如果是属性node   表示获取一组属性的值

                            Elements 输出用, 存放当前一组目标属性值, 每个pair表示一个属性对, pair.first 表示属性, pair.second 表示属性值

 如果是元素node  Undefined

3. xpath原始运算

构建 xpath, 执行原始xpath运算

void
EvalValue(
const
string& epath, string& value);

xml工具使用

可以在shell中使用该工具快速获取,修改xml node.

xmleditor options:
-h [ --help ] help message
-f [ --file ] arg xml path
-t [ --type ] arg (=attr) node type: attr, element
-p [ --epath ] arg externed xml node path
-a [ --action ] arg (=get) action: add, del, set, get, eval
-v [ --value ] arg value

eg. 

增加属性

  • ./xmleditor -f example.xml -p "/configure/basic/log" -v "time=1024" -a add

  old:   <log dir="./log/" schedule="hourly" max_file_index="1000"/>

  new: <log dir="./log/" schedule="hourly" max_file_index="1000" time="1024"/>

删除属性

  • ./xmleditor -f ./example.xml -p "/configure/basic/log" -v "dir" -a del

  old:   <log dir="./log/" schedule="hourly" max_file_index="1000"/>

  new: <log schedule="hourly" max_file_index="1000" />

修改属性

  • ./xmleditor -f ./example.xml -p "/configure/basic/log" -v "dir=/mnt/raid5/omatrix_core/23/log/" -a set

  old:   <log dir="./log/" schedule="hourly" max_file_index="1000"/>

  new: <log dir="/mnt/raid5/omatrix_core/23/log/" schedule="hourly" max_file_index="1000"/>

获取属性

  • ./xmleditor -f ./example.xml -p "/configure/basic/log/@dir" 

  返回: /mnt/raid5/omatrix_core/23/log/

xpath运算: 直接执行xpath, 输出运算后返回的结果, 个人认为对于学习xpath比较有帮助

./xmleditor -f ./omatrix.xml -a eval -p "//basic/log/@dir"
  
nodeset =
    
nodeNr: 1                          //当前xpath一共定位到的节点数
    
Node: 0                            //当前定位到的节点index
    
Xline: 5                           //当前定位到的节点在xml中哪一行
    
Xpath: /configure/basic/log/@dir   //当前定位到的节点的完整xpath
    
NodeType: 2                       //当前定位到的节点的类型
    
Name: dir                         //当前定位到的节点的name
    
Content: ./log/                   //当前定位到的节点的content节点的类型:
 
 
其中节点的类型:
   
ELEMENT_NODE     =1,
   
ATTRIBUTE_NODE   =2,
   
TEXT_NODE        =3,   COMMENT_NODE     =8,

xpath简介

xpath即xml 路径语言, 它是W3C的一个标准, 简单说就是定位XML文件中节点的方法.

1.所谓节点(node), 就是XML文件的最小构成单位,一共分成7种。

  • - element(元素节点)
  • - attribute(属性节点)
  • - text (文本节点)
  • - comment (注释节点)
  • - namespace (名称空间节点)
  • - processing-instruction (处理命令节点)
  • - root (根节点)

2.xpath通过"路径表达式"(Path Expression)来选择节点,选择节点的基本规则.

  •  nodename(节点名称):  表示选择该节点的所有子节点
  • "/":                                  表示选择根节点
  • "//":                                 表示选择当前节点的所有子节点
  • "@":                               表示选择某个属性

3.xpath 通配符

  •  *: 表示匹配任何元素节点。
  • @*: 表示匹配任何属性值。
  • node()表示匹配任何类型的节点

4.列举几个xpath的例子

example.xml
1
2
3
4
5
6
7
8
9
10
11
<?
xml
version
=
"1.0"
?>
<
configure
>
  
<
data
count
=
"5"
>
      
<!--tag  参照total_fields.h-->
      
<
field
id
=
"1"
name
=
"report_sec"
tag
=
"kreport_sec"
type
=
"60"
/>
<!--from Deliver-->
      
<
field
id
=
"2"
name
=
"start_time"
tag
=
"kstart_time"
type
=
"40"
/>
      
<
field
id
=
"3"
name
=
"tp_oa"
tag
=
"ktp_origin_address"
type
=
"30"
> 717171</
field
>
      
<
field
id
=
"4"
name
=
"response_time"
tag
=
"kresponse_time"
type
=
"40"
/>
      
<
field
id
=
"4"
name
=
"up_retrans_pkts"
tag
=
"kup_retrans_pkts"
type
=
"12"
/>
  
</
data
>
</
configure
>

  1)定位node:

  • 定位 data :                                                         /configure/data//
  • 定位第index个field:                                         /configure/field[1]
  • 定位包含某个属性的field:                                /configure/field[@id=5] 
  • 定位包含多个属性的field :                               /configure/field[@id=5][name=\"up_retrans_pkts\"] 

  2)定位text:

  • 定位 data 的text:                                              /configure/data/text()
  • 定位 data 的第index个text:                            /configure/data/text()[1]
  • 定位包含某个属性的field的text:                      /configure/data/field[@id=3]/text()   

  3)定位注释:

  • 定位data下的所有注释:                                   /configure/data/comment()
  • 定位data下的第index个注释:                         /configure/data/comment()[1]   

  4)定位属性:(当前最常用到)

  • 定位 count属性:                                               /configure/data/@count
  • 定位 第index个field 的 id属性:                      /configure/field[1]/@id
  • 定位 第index个field 的 所有属性:                  /configure/field[1]/@*
  • 定位 包含某个属性的field的 name 属性:        /configure/field[@id=1]/@name
  • 定位 包含某个属性的field的 所有属性:          /configure/field[@id=1]/@*
  • 定位 包含某个属性的field的 id 属性:             /configure/field[@name=\"uid\"]/@id                                    //注意转义\"
  • 定位 data/field下的所有子节点的属性:          /configure/filed/@*
  • 定位 data/field下的所有的name属性:            /configure/filed/@name
  • 定位 包含多个属性的field的 type属性:          /configure/field[@id=5][name=\"up_retrans_pkts\"]/@type 

  5)定位其他:

  • 定位 /configure/data 下的所有节点:             /configure/data/node()                                                          //该定位包含的节点有: elementtext节点, text节点, comment节点, 但不包含attribute"节点

  6)总结:

  • 定位node是基础, 只要定位到node, 加 "@attr" 即是定位到属性;    加 "text()" 即是定位到text;     加 "comment()" 即是定位到comment
  • 对当前的node加一定的条件(条件都要写到[]里面)就可以进一步筛选node,    eg. 可以限定多个属性来定位node, field[@id=5][name=\"up_retrans_pkts\"]; 可以限定index来定位node, /configure/field[1] 

  7)xpath 链接

    前两篇比较基础,短小, 仔细阅读后会对xpath有大致的了解并能基本运用, 后面两篇则更加深入, 全面.

    •  

转载于:https://www.cnblogs.com/457220157-FTD/p/4104269.html

你可能感兴趣的文章
自适应电脑、手机和iPad的网页设计方法
查看>>
android mvc
查看>>
CAKeyframeAnimation 关键帧动画
查看>>
flash版本更新导致shopex后台上传图片无效的问题
查看>>
Spring Bean生命周期详解
查看>>
JQuery实现聊天对话框
查看>>
windbg vmware配置
查看>>
使用PowerShell 监控运行时间和连接情况
查看>>
自定义控件ToggleButton滑动开关
查看>>
Hello, WebView
查看>>
使用css3属性,大部分浏览器要识别前缀
查看>>
c# webapi上传、读取、删除图片
查看>>
java 反射
查看>>
【批处理学习笔记】第二十五课:间接传递
查看>>
搬到CSDN,两个同时用,以防万一
查看>>
python基础--模块&包
查看>>
selenium webdriver 学习笔记(三)
查看>>
(六)软件测试分工
查看>>
hdu 1598 find the most comfortable road
查看>>
Linux多线程──读者写者问题
查看>>