赞
踩
第三方库TinyXML2是简单、小型、高效、开源的C++ XML文件解析库,可以很方便的应用到现有的项目之中,非常适合解析XML文件,存储简单数据,配置文件以及对象序列化等数据量不是很大的操作。
TinyXML2详细介绍与详见:TinyXML2官网。
TinyXML2可以通过其Github主页获取源代码,具体来说可以采用git clone
命令或直接下载其ZIP压缩包,git clone
命令的调用情况如下:
git clone https://github.com/leethomason/tinyxml2
在命令行进入tinyxml2
目录下,使用下列命令编译并安装TinyXML2,命令执行情况如下(其中的$
符号为shell下的命令提示符):
$ sudo make install
mkdir -p /usr/local
mkdir -p /usr/local/bin
mkdir -p /usr/local/lib
mkdir -p /usr/local/include
install xmltest /usr/local/bin/xmltest
install -m 644 tinyxml2.h /usr/local/include/tinyxml2.h
install -m 644 libtinyxml2.a /usr/local/lib/libtinyxml2.a
由此,便将tinyxml2
库安装到了本地环境中,在tinyxml2
目录下执行如下命令,可以运行TinyXML2的测试代码:
$ xmltest
该例程执行时用到的xml文件均位于tinyxml2
目录中的resources
目录下,该程序执行结束后的终端提示如下图所示:
由此说明tinyxml2
库已经成功安装完成。
将TinyXML2安装到本地环境之后,下面演示TinyXML2的简单使用:
将TinyXML2源码文件夹中的文件xmltest.cpp
和resources/dream.xml
复制到目标文件夹用于示例演示。
这里,在xmltest.c
文件中引用了头文件tinyxml2.h
:
#include "tinyxml2.h"
同时声明了TinyXML2的命名空间:
using namespace tinyxml2;
另外,在main函数中定义:若程序的参数大于1,则创建XMLDocument
对象并加载程序参数指定的文件,最后若成功加载文件,则输出相关处理时间,该部分代码如下所示。
if ( argc > 1 ) { XMLDocument* doc = new XMLDocument(); clock_t startTime = clock(); doc->LoadFile( argv[1] ); clock_t loadTime = clock(); int errorID = doc->ErrorID(); delete doc; doc = 0; clock_t deleteTime = clock(); printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID ); if ( !errorID ) { printf( "Load time=%u\n", (unsigned)(loadTime - startTime) ); printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) ); printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) ); } exit(0); }
使用如下命令编译程序:
$ g++ -o xmltest xmltest.cpp -ltinyxml2
若出现找不到头文件或找不到静态库的错误提示,还可以手动指定头文件目录(-I
)和库文件目录(-L
):
$ g++ -o xmltest xmltest.cpp -I /usr/local/include -L /usr/local/lib -ltinyxml2
输入如下命令,执行示例程序:
$ xmltest dream.xml
可以看到程序输出如下,即程序成功加载了XML文件dream.xml。
下面通过在ROS工作空间创建一个ROS功能包tinyxml_test
使用TinyXML2解析ROS中的Launch文件,以此演示TnyXML2在ROS中的使用。
下面是该功能包的package.xml
文件:
<?xml version="1.0"?> <package format="2"> <name>tinyxml_test</name> <version>0.0.0</version> <license>TODO</license> <maintainer email="jacky@geometricalpal.com">jacky</maintainer> <description>The tinyxml_test package</description> <buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <build_depend>tf</build_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>tf</build_export_depend> <exec_depend>roscpp</exec_depend> <exec_depend>tf</exec_depend> </package>
功能包中的Node源文件tinyxml_test_node.cpp
代码如下:
#include <ros/ros.h> #include <ros/package.h> #include <tf/transform_broadcaster.h> #include <tinyxml2.h> #include <iostream> #include <string> #include <sstream> #include <vector> #include <map> using namespace tinyxml2;//使用tinyxml2命名空间 using namespace std; /* 功能函数 */ float String2Float(std::string numStr){ std::stringstream ss(numStr); float num; ss>>num; return num; } int main(int argc, char **argv) { ros::init(argc, argv, "tinyxml_test_node"); ros::NodeHandle nh("~"), nh_param("~"); std::string tf_launch_file; //注:"test.launch"文件位于catkin_ws/src/tinyxml_test/launch/目录下 nh_param.param<std::string>("tf_launch_file", tf_launch_file,"test.launch"); /*Load launch file to get the tf args.*/ XMLDocument* doc = new XMLDocument(); std::map<std::string,tf::StampedTransform> stampedTransformMap;//用于存储多个不同坐标系之间的转换关系 std::string filePath = ros::package::getPath("tinyxml_test");//获取tinyxml_test功能包的绝对路径 filePath+="/launch/"; filePath+=tf_launch_file; doc->LoadFile( filePath.c_str() ); int errorID = doc->ErrorID(); if(errorID){ ROS_FATAL("[radar_freespace] Failed to load launch file %s.", filePath.c_str()); return -1; } ROS_INFO( "[radar_freespace] Launch file '%s' loaded.", filePath.c_str()); XMLElement* rootElement = doc->RootElement();//获得根元素,即launch std::cout<<"Root Element:"<<rootElement->Value()<<std::endl; for(const XMLElement* element =rootElement->FirstChildElement();element;element=element->NextSiblingElement()){ const XMLAttribute* argsAttr = element->FindAttribute("args"); std::string argsAttrStr=std::string(argsAttr->Value()); std::cout<<"Args Attribute:"<<argsAttrStr<<std::endl; std::stringstream ss(argsAttrStr); std::vector<std::string> argStrVec; std::string tmpArgStr = ""; while (std::getline(ss, tmpArgStr, ' ')) { argStrVec.push_back(tmpArgStr); } tf::Transform transform; transform.setOrigin(tf::Vector3(String2Float(argStrVec.at(0)),String2Float(argStrVec.at(1)),String2Float(argStrVec.at(2)))); tf::Quaternion quaternion; quaternion.setRPY(String2Float(argStrVec.at(5)),String2Float(argStrVec.at(4)),String2Float(argStrVec.at(3))); transform.setRotation(quaternion); stampedTransformMap[argStrVec.at(6)]=tf::StampedTransform(transform,ros::Time::now(),argStrVec.at(6),argStrVec.at(7)); //输出launch文件中记录的坐标系转换关系 std::cout<<stampedTransformMap[argStrVec.at(6)].getOrigin().x()<<","<<stampedTransformMap[argStrVec.at(6)].getOrigin().y()<<","<<stampedTransformMap[argStrVec.at(6)].getOrigin().z()<<","; std::cout<<stampedTransformMap[argStrVec.at(6)].getRotation().getW()<<","<<stampedTransformMap[argStrVec.at(6)].getRotation().getX()<<","<<stampedTransformMap[argStrVec.at(6)].getRotation().getY()<<","<<stampedTransformMap[argStrVec.at(6)].getRotation().getZ()<<std::endl; } delete doc; //删除对象 doc = NULL; //避免野指针 ros::spin(); return 0; }
该Node能够利用TinyXML2解析本功能包中的Launch文件(XML格式),该文件为位于catkin_ws/src/tinyxml_test/launch/目录下的文件test.launch
,并且最后可以根据读取的launch文件输出其中保存的tf坐标转换信息。test.launch
文件的内容如下:
<?xml version="1.0"?>
<launch>
<node pkg="tf" type="static_transform_publisher" name="sensor_frame_to_world" args="2 2 2 0 0 0 world sensor_frame 100" />
<node pkg="tf" type="static_transform_publisher" name="imu_to_sensor_frame" args="0 0 0 0 0 0 sensor_frame imu 100" />
<node pkg="tf" type="static_transform_publisher" name="lidar_to_sensor_frame" args="1 1 1 0 0 0 sensor_frame lidar 100" />
</launch>
要编译该功能包,还需要修改其CMakeLists.txt文件,添加必要的功能包、包含目录、源代码和链接库等。该文件的完整内容如下:
cmake_minimum_required(VERSION 2.8.3) project(tinyxml_test) ## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS roscpp roslib tf ) ################################### ## catkin specific configuration ## ################################### catkin_package( LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS roscpp tf ) ########### ## Build ## ########### ## Specify additional locations of header files ## Your package locations should be listed before other locations include_directories( ${catkin_INCLUDE_DIRS} ) ## Declare a C++ executable ## With catkin_make all packages are built within a single CMake context ## The recommended prefix ensures that target names across packages don't collide add_executable(${PROJECT_NAME}_node src/tinyxml_test_node.cpp) ## Specify libraries to link a library or executable target against target_link_libraries(${PROJECT_NAME}_node -ltinyxml2 ${catkin_LIBRARIES} ) ############# ## Install ## ############# ## Mark executables and/or libraries for installation install( TARGETS ${PROJECT_NAME}_node ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
需要注意的是:由于程序需要调用第三方库TinyXML2,因此需要在CMakeLists.txt文件中的find_package
选项中添加roslib
功能包,并在target_link_libraries
选项中指定链接该静态库(-ltinyxml2
)。
最后,执行命令catkin_make
将功能包编译成功之后,使用如下命令运行节点(需提前运行roscore
节点):
$ rosrun tinyxml_test tinyxml_test_node
程序能够输出launch文件中保存的tf坐标转换信息:
大功告成!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。