XML文件按照元素标记来存储数据,通过遍历这些元素标记可以得到XML文件中所保存的数据。在C++/CX的类库中并未定义用于解析XML文件的类,但C++提供了能解析XML文件的框架和类库,如msxml4、libxml、IXMLDOM和TinyXML等,在使用C++/CX编写应用程序时可以通过C++提供的框架和类库来解析XML文件。TinyXML是一个轻量级解析XML的框架,本节将介绍如何使用此框架来解析一个XML文件。

TinyXML框架包含了以下的类和函数,通过使用这些类和函数可以方便地读取一个XML文件中的数据。

  • TiXmlDocument类,表示整个XML文件的文档类。
  • TiXmlDeclaration类,表示XML文件的声明部分的声明类。
  • TiXmlElement类,表示XML中的节点元素的元素类。
  • RootElement函数,用于得到XML文件中的根节点。
  • FirstChildElement函数,用于得到第一个子节点。
  • FirstAttribute函数,用于得到节点的第一个属性。
  • NextSiblingElement函数,用于得到下一个节点。
  • LoadFile函数,用于加载XML文件。

简单介绍了TinyXML框架之后,接下来通过一个具体的示例来介绍如何使用TinyXML框架解析XML文件。在Visual Staudio 2012中新建一个Visual C++的Windows应用商店的空白应用程序项目,并命名为CookBookDemo。

由于在C++的标准库中并未包含TinyXML框架,因此在使用TinyXML框架来解析XML文件之前,需要将此框架中的几个主要文件添加到项目里,这些文件分别是tinystr.cpp、tinystr.h、tinyxml.cpp、tinyxml.h、tinyxmlerror.cpp和tinyxmlparser.cpp。TinyXML框架的压缩包可以从"http://sourceforge.net/projects/tinyxml/"网站下载,然后按如下的步骤添加上述的主要文件。

右键点击解决方案资源管理器窗口中的项目图标,在弹出的菜单栏中选中"添加",并在"添加"的子菜单栏中选择"现有项",接着在出现的"添加现有项"窗口中选择上述压缩包中的文件,单击"添加"按钮将这些文件添加到项目中。在项目中添加"现有项"如图20-3所示。

图20-3 添加"现有项"

添加了上述TinyXML框架中的主要文件以后,需要在项目中引用相应的头文件,以便能使用TinyXML框架中的类和函数来解析XML文件。打开MainPage.xaml.cpp源文件,使用include关键字引用tinyxml.h头文件,代码如下所示:

#include "tinyxml.h"

引用了tinyxml.h头文件以后,接着为了能在项目中编译tinystr.cpp、tinyxml.cpp 、tinyxmlerror.cpp和tinyxmlparser.cpp源文件,需要分别打开这些源文件,并在文件的开头引用项目中默认的pch.h头文件。代码如下所示:

#include "pch.h"

接下来在项目中添加一个名为"CookBookXMLFile.xml"的XML文件,后面将解析这个XML文件。在解决方案资源管理器窗口中右键点击项目图标,在弹出的菜单栏中选中"添加", 并在"添加"的子菜单栏中选择"新建项",接着在出现的"添加新项"窗口中选择Visual C++菜单栏的"Web"选项,选中"XML文件",添加名为"CookBookXMLFile.xml"的XML文件。在"添加新项"窗口中添加XML文件的步骤如图20-4所示。

图20-4 在"添加新项"窗口中添加XML文件

添加了CookBookXMLFile.xml文件以后,接下来在这个文件中添加数据,后面将说明如何解析此文件来获取这些数据。CookBookXMLFile.xml文件中的代码如下所示:

<?xml version="1.0" encoding="gb2312"?>

<CookBook>

<CookStyle Name="粤菜" Image="冬瓜盅.jpg">

</CookStyle>

<CookStyle Name="川菜" Image="四川麻辣火锅.jpg">

</CookStyle>

<CookStyle Name="闽菜" Image="全丝烩鱼翅.jpg">

</CookStyle>

<CookStyle Name="东北菜" Image="东北汆白肉.jpg">

</CookStyle>

</CookBook>

在CookBookXMLFile.xml文件中,声明编码格式为"gb2312",并定义一个名为"CookBook"的节点,将这个节点作为根节点。在根节点中定义四个名为"CookStyle"的子节点,并在每一个CookStyle节点中定义两个属性Name和Image,分别用于保存菜名和项目中图片的路径。为了能通过Image属性中所保存的图片路径来在前台界面显示图片,需要按照上述添加"现有项"的步骤来添加对应的图片。

在CookBookXMLFile.xml文件中添加了数据以后,接下来定义一个FeedItem类,用来保存CookBookXMLFile.xml文件被解析后得到的数据。打开MainPage.xaml.h头文件,并在此头文件中定义FeedItem类,代码如下所示:

//定义FeedItem类

[Windows::UI::Xaml::Data::Bindable]

public ref class FeedItem sealed

{

public:

    //FeedItem构造函数

    FeedItem(void){}

public:

    //保存XML中Image属性的值

    property Platform::String^ Image;

    //保存XML中Name属性的值

    property Platform::String^ Name;

};

上面的代码在FeedItem类中定义构造函数FeedItem,接着声明两个属性Name和Image,其中Name属性用来保存CookBookXMLFile.xml文件中CookStyle节点的Name属性值,Image属性用来保存CookStyle节点的Image属性值。

定义了FeedItem类之后,接下来布局前台界面。打开MainPage.xaml文件,并指定Grid元素中的Background属性为"White",接着在此元素中添加如下的代码:

<!-- 菜系列表 -->

<ListView x:Name="CookBookListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding}" Margin="50,50,0,0">

<ListView.ItemTemplate>

<DataTemplate>

<Grid Margin="10,10,0,0">

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto"></ColumnDefinition>

<ColumnDefinition Width="*"></ColumnDefinition>

</Grid.ColumnDefinitions>

<Image x:Name="CookImage" Source="{Binding Path=Image}" Grid.Column="0" Width="50" Height="50"></Image>

<TextBlock x:Name="CookName" Text="{Binding Path=Name}" Grid.Column="1" Foreground="Black"></TextBlock>

</Grid>

</DataTemplate>

</ListView.ItemTemplate>

</ListView>

在上述代码中,添加一个名为"CookBookListView"的ListView控件,使用这个控件以列表的形式显示FeedItem类的对象所保存的数据。接着为ListView控件添加一个DataTemplate模版,并在DataTemplate模版中添加一个Image控件和一个TextBlock控件,其中FeedItem类的Image属性绑定到了Image控件的Source属性上,FeedItem类的Name属性绑定到了TextBlock控件的Text属性上。

布局好前台界面以后,接下来解析CookBookXMLFile.xml文件,并将CookBookXMLFile.xml文件中的数据显示到前台界面中。

由于使用TinyXML框架解析XML文件得到的数据为const char类型,为了将const char类型的数据保存到FeedItem类的对象中,需要对这些数据的类型进行转换。这里使用ChangeToWchar函数来转换数据的类型,在MainPage.xaml.h头文件中声明ChangeToWchar函数,代码如下所示:

private:

    //声明ChangeToWchar函数

    wchar_t* ChangeToWchar(const char* valueChar);

声明了ChangeToWchar函数以后,接着打开MainPage.xaml.cpp源文件,并添加ChangeToWchar函数的实现代码,具体代码如下所示:

wchar_t* CookBookDemo::MainPage::ChangeToWchar(const char* valueChar)

{

    //使用MultiByteToWideChar来转换

    size_t wlen =MultiByteToWideChar(CP_ACP,0, valueChar,strlen(valueChar),NULL,0);

    //定义wchar_t类型指针wStr

    wchar_t *wStr = new wchar_t[wlen+1];

    //使用MultiByteToWideChar函数来转换

    wlen = MultiByteToWideChar(CP_ACP,0, valueChar,strlen(valueChar),wStr,wlen);

    wStr[wlen] = L'\0';

    //返回wStr

    return wStr;

}

在上面的代码中,首先调用MultiByteToWideChar函数得到将参数valueChar转换成wchar_t类型时所需要的内存空间大小,并赋值给一个size_t类型的变量wlen。然后创建一个大小为wlen+1的wchar_t类型的数组,使用一个wchar_t类型的指针wStr指向此数组。接着以wStr指针和wlen变量作为参数调用MultiByteToWideChar函数来将参数valueChar中的值转换成wchar_t类型,并保存到wStr指针所指向的数组中。最后给wStr指针所指向的数组添加结束标志"\0",并返回wStr指针。

添加了ChangeToWchar函数的实现代码以后,接下来在MainPage.xaml.h头文件中添加如下的代码,用于声明解析CookBookXMLFile.xml文件的LoadCookStyle函数。

public:

    //解析XML文件

    void LoadCookStyle();

声明了LoadCookStyle函数以后,接下来在MainPage.xaml.cpp源文件的MainPage构造函数中调用LoadCookStyle函数,以便于在项目启动时解析CookBookXMLFile.xml文件。MainPage构造函数的实现代码如下所示:

MainPage::MainPage()

{

    InitializeComponent();

    //解析XML文件

    LoadCookStyle();

}

接下来在MainPage.xaml.cpp源文件中添加LoadCookStyle函数的实现代码,具体代码如下所示:

//解析XML文件

void CookBookDemo::MainPage::LoadCookStyle()

{

    //创建一个Vector<FeedItem^>类型的集合items

    Platform::Collections::Vector<FeedItem^>^ items=ref new Platform::Collections::Vector<FeedItem^>();

    //加载存放菜谱数据的XML文件

    TiXmlDocument* xmlDocument= new TiXmlDocument("CookBookXMLFile.xml");

    xmlDocument->LoadFile();

    //获得根节点CookBook

    TiXmlElement* cookBookElement = xmlDocument->RootElement();

    //获得CookBook下的第一个子节点

    TiXmlElement* cookStyleNode = cookBookElement->FirstChildElement();

    //将CookBook中的CookStyle节点解析出来

    while(cookStyleNode != nullptr)

    {        

        //创建数据源CookBookFeedItem,用于绑定到前台页面

        CookBookDemo::FeedItem^ cookBookFeedItem=ref new CookBookDemo::FeedItem();

        //将得到的CookStyle的Name属性值转换为wchar_t

        const char* firstAttributeValue=cookStyleNode->FirstAttribute()->Value();

        wchar_t* nameWstr=ChangeToWchar(firstAttributeValue);

        //将得到的CookStyle的Image属性值转换为wchar_t

        const char* nextAttributeValue=cookStyleNode->FirstAttribute()->Next()->Value();

        wchar_t* imageWstr=ChangeToWchar(nextAttributeValue);

        //将转换后的值赋给cookBookFeedItem->Name

        cookBookFeedItem->Name=ref new Platform::String(nameWstr);

        //将转换后的值赋给cookBookFeedItem->Image

        cookBookFeedItem->Image=ref new Platform::String(imageWstr);

        //将cookBookFeedItem添加到items

        items->Append(cookBookFeedItem);

        //遍历下一个CookStyle节点

        cookStyleNode=cookStyleNode->NextSiblingElement();

    }

    //设置CookBookListView上下文

    CookBookListView->DataContext=items;

}

在LoadCookStyle函数中,首先创建一个Vector<FeedItem^>类型的集合items,接着以CookBookXMLFile.xml文件的路径作为参数调用TiXmlDocument类的构造函数得到一个TiXmlDocument类型的对象,并使用xmlDocument指针指向此对象。然后调用xmlDocument对象的LoadFile函数来加载CookBookXMLFile.xml文件。

接下来调用xmlDocument对象的RootElement函数得到CookBookXMLFile.xml文件的根节点,并使用一个TiXmlElement类型的指针cookBookElement指向这个根节点。接着调用cookBookElement对象的FirstChildElement函数得到根节点中的第一个CookStyle子节点,使用TiXmlElement类型的指针cookStyleNode指向此节点。

当cookStyleNode指针不为空指针时,执行while循环中的代码,创建一个FeedItem类的对象cookBookFeedItem,用来保存数据。接着调用cookStyleNode对象的FirstAttribute函数得到CookStyle节点中的Name属性,通过Value函数得到Name属性的值。同样调用Next函数得到CookStyle节点中的Image属性,通过Value函数得到Image属性的值。然后调用ChangeToWchar函数将Name属性和Image属性的值转换成wchar_t类型,并通过创建String类的对象将这两个属性的值进一步转换成String类型。接着将Name属性和Image属性的值赋值给cookBookFeedItem对象的Name属性和Image属性,并将cookBookFeedItem对象添加到items集合中。最后将items集合赋值给ListView控件的DataContext属性,以便能将cookBookFeedItem对象所保存的数据显示到前台界面中。

运行项目,将显示如图20-5所示的界面。

图20-5 解析XML得到的数据

Win10系列:VC++ XML文件解析的更多相关文章

  1. Android之AndroidManifest.xml文件解析

    转自:Android学习笔记之AndroidManifest.xml文件解析 一.关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文 ...

  2. 通过正则表达式实现简单xml文件解析

    这是我通过正则表达式实现的xml文件解析工具,有些XHTML文件中包含特殊符号,暂时还无法正常使用. 设计思路:常见的xml文件都是单根树结构,工具的目的是通过递归的方式将整个文档树装载进一个Node ...

  3. 八、Android学习第七天——XML文件解析方法(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 八.Android学习第七天——XML文件解析方法 XML文件:exten ...

  4. android基础知识13:AndroidManifest.xml文件解析

    注:本文转载于:http://blog.csdn.net/xianming01/article/details/7526987 AndroidManifest.xml文件解析. 1.重要性 Andro ...

  5. 9.XML文件解析

    一.XML简介 XML(EXtensible Markup Language),可扩展标记语言 特点:XML与操作系统.编程语言的开发平台无关 实现不同系统之间的数据交换 作用:数据交互 配置应用程序 ...

  6. Python实现XML文件解析

    1. XML简介 XML(eXtensible Markup Language)指可扩展标记语言,被设计用来传输和存储数据,已经日趋成为当前许多新生技术的核心,在不同的领域都有着不同的应用.它是web ...

  7. Python3将xml文件解析为Python对象

    一.说明 从最开始写javascript开始,我就很烦感使用getElementById()等函数来获取节点的方法,获取了一个节点要访问其子孙节点要么child半天要么就再来一个getElementB ...

  8. XML文件解析-DOM4J方式和SAX方式

    最近遇到的工作内容都是和xml内容解析相关的. 1图片数据以base64编码的方式保存在xml的一个标签中,xml文件通过接口的方式发送给我,然后我去解析出图片数据,对图片进行进一步处理. 2.xml ...

  9. java基础之概谈xml文件解析

    XML已经成为一种非常通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便. 诸多web应用框架,其可配置的编程方式,给我们的开发带来了非常大程度的便捷,但细细 ...

随机推荐

  1. NativeWindow_01_CreateWindow(Ex)_VC6

    1. #include <windows.h> LRESULT CALLBACK ProcWindow(HWND hwnd, UINT uMsg, WPARAM wParam, LPARA ...

  2. python模块(4)

    re正则 re.match 从头开始匹配 re.search 匹配包含 re.findall 把所有匹配到的字符放到以列表中的元素返回(没有group()方法) re.splitall 以匹配到的字符 ...

  3. 使用pipeline减少与redis交互次数

    1.redis_pipeline=redis_cli.pipeline() 2.redis_pipeline.setex()此语句可写多条 3.redis_pipeline.execute() # # ...

  4. 关于JS历史

      js由来        95年那时,绝大多数因特网用户都使用速度仅为28.8kbit/s 的“猫”(调制解调器)上网,但网页的大小和复杂性却不断增加.为完成简单的表单验证而频繁地与服务器交换数据只 ...

  5. C++ 实现sqilte创建数据库插入、更新、查询、删除

    C/C++ Interface APIs Following are important C/C++ SQLite interface routines, which can suffice your ...

  6. lua中pairs 和 ipairs 的区别

    1.table中存储值的时候,是按照顺序存储的,存储 k-v 的时候,是按照 k 的哈希值存储的. 2.ipairs --- 只能输出 table 中的值,并且不可输出nil,遇到 ni l就退出 p ...

  7. Spring学习笔记(入门)

    1.基本看了一下,spring就是利用这个框架帮助我们实例化对象的工具.首先我们需要引入jar包,pom.xml如下: <project xmlns="http://maven.apa ...

  8. Win7无法保存共享帐户密码

    每次机器重启完之后,网络共享的密码总是要重新输入. [记住我的凭据]选项不起作用. 查到了下面百度经验的文章,挺靠谱的. https://jingyan.baidu.com/article/59a01 ...

  9. 开机出现grub界面(待尝试)

    开机出现grub界面 试一下这个命令: grub> rootnoverify (hd0,0) grub> chainloader +1 grub> boot 这样就可以进入到wind ...

  10. rabbimq

    问题 启动RabbitMQ后,没法访问Web管理页面   解决 RabbitMQ安装后默认是不启动管理模块的,所以需要配置将管理模块启动 启动管理模块命令如下   rabbitmqctl start_ ...