现在的位置: 首页 > 综合 > 正文

xml

2013年08月31日 ⁄ 综合 ⁄ 共 33394字 ⁄ 字号 评论关闭

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head>
<style type="text/css">
.zf {
    font-size : small;
    background-color : #fffbc0;
    border-style : solid;
    border-color : #fff949;
    border-width : 1px;
    color : #0d039c;
  }
</style>

<title>Mini-XML 程序员开发手册, Version 2.5</title>
<meta name="author" content="Michael R. Sweet">
<meta name="Translator" content="ZhuFeng">
<meta name="copyright" content="Copyright 2003-2008">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><style type="text/css"><!--
BODY { font-family: sans-serif }
H1 { font-family: sans-serif }
H2 { font-family: sans-serif }
H3 { font-family: sans-serif }
H4 { font-family: sans-serif }
H5 { font-family: sans-serif }
H6 { font-family: sans-serif }
SUB { font-size: smaller }
SUP { font-size: smaller }
PRE { font-family: monospace }
A { text-decoration: none }
--></style>
</head><body>
<h1 align="center"><a name="CONTENTS"> 目录</a></h1>
<div class="zf" align="right">中文翻译:Z.F , mail: zhfjyq@gmail.com ,<a href="http://blog.csdn.net/bluesonic">http://blog.csdn.net/bluesonic</a></div>
<br>
<br><b><a href="#INTRO">序言</a></b>
<ul>
<li><a href="#1_1">本文结构 </a></li>
<li><a href="#1_2">词法约定 </a></li>
<li><a href="#1_3">缩略语 </a></li>
<li><a href="#1_4">其他参考 </a></li>
<li><a href="#1_5">法律信息 </a></li>
</ul>
<b><a href="#INSTALL">构建,安装,以及打包Mini-XML </a></b>
<ul>
<li><a href="#2_1">编译 Mini-XML</a>
<ul>
<li><a href="#2_1_1">使用 Visual C++ 进行编译</a></li>
<li><a href="#2_1_2"> 使用命令行工具进行编译 </a></li>
</ul>
</li>
<li><a href="#2_2">安装 Mini-XML</a></li>
<li><a href="#2_3">创建 Mini-XML 包</a></li>
</ul>
<b><a href="#BASICS">Mini-XML 入门</a></b>
<ul>
<li><a href="#3_1">基础知识</a></li>
<li><a href="#3_2">节点</a></li>
<li><a href="#3_3">创建 XML 文档 </a></li>
<li><a href="#3_4">加载 XML</a></li>
<li><a href="#3_5">保存 XML</a>
<ul>
<li><a href="#3_5_1">控制自动输出换行 </a></li>
</ul>
</li>
<li><a href="#3_6">搜索和遍历节点 </a></li>
</ul>
<b><a href="#ADVANCED">更多的 Mini-XML 编程技术</a></b>
<ul>
<li><a href="#LOAD_CALLBACKS">加载回调函数 </a></li>
<li><a href="#SAVE_CALLBACKS">保存回调函数 </a></li>
<li><a href="#4_3">用户定义数据类型</a></li>
<li><a href="#4_4">改变节点的值</a></li>
<li><a href="#4_5">格式化文本</a></li>
<li><a href="#4_6">索引</a></li>
<li><a href="#4_7">SAX (流方式解析) 加载文档</a></li>
</ul>
<b><a href="#MXMLDOC">使用 mxmldoc 工具</a></b>
<ul>
<li><a href="#5_1">基础知识</a></li>
<li><a href="#5_2">为你的代码添加注释</a></li>
<li><a href="#5_3">标题、分段名和简介</a></li>
</ul>
<b><a href="#LICENSE">Mini-XML 许可信息</a></b>
<br>
<br><b><a href="#RELNOTES">发行说明</a></b>
<ul></ul>
<b><a href="#REFERENCE">库参考手册</a></b>
<ul>
<li><a href="#8_1">目录</a></li>
<li><a href="#FUNCTIONS">函数</a>
<ul>
<li><a href="#mxmlAdd">mxmlAdd</a></li>
<li><a href="#mxmlDelete">mxmlDelete</a></li>
<li><a href="#8_2_3">mxmlElementDeleteAttr</a></li>
<li><a href="#mxmlElementGetAttr">mxmlElementGetAttr</a></li>
<li><a href="#mxmlElementSetAttr">mxmlElementSetAttr</a></li>
<li><a href="#8_2_6">mxmlElementSetAttrf</a></li>
<li><a href="#mxmlEntityAddCallback">mxmlEntityAddCallback</a></li>
<li><a href="#mxmlEntityGetName">mxmlEntityGetName</a></li>
<li><a href="#mxmlEntityGetValue">mxmlEntityGetValue</a></li>
<li><a href="#mxmlEntityRemoveCallback">mxmlEntityRemoveCallback</a></li>
<li><a href="#mxmlFindElement">mxmlFindElement</a></li>
<li><a href="#mxmlIndexDelete">mxmlIndexDelete</a></li>
<li><a href="#mxmlIndexEnum">mxmlIndexEnum</a></li>
<li><a href="#mxmlIndexFind">mxmlIndexFind</a></li>
<li><a href="#mxmlIndexNew">mxmlIndexNew</a></li>
<li><a href="#mxmlIndexReset">mxmlIndexReset</a></li>
<li><a href="#mxmlLoadFd">mxmlLoadFd</a></li>
<li><a href="#mxmlLoadFile">mxmlLoadFile</a></li>
<li><a href="#mxmlLoadString">mxmlLoadString</a></li>
<li><a href="#8_2_20">mxmlNewCDATA</a></li>
<li><a href="#8_2_21">mxmlNewCustom</a></li>
<li><a href="#mxmlNewElement">mxmlNewElement</a></li>
<li><a href="#mxmlNewInteger">mxmlNewInteger</a></li>
<li><a href="#mxmlNewOpaque">mxmlNewOpaque</a></li>
<li><a href="#mxmlNewReal">mxmlNewReal</a></li>
<li><a href="#mxmlNewText">mxmlNewText</a></li>
<li><a href="#mxmlNewTextf">mxmlNewTextf</a></li>
<li><a href="#8_2_28">mxmlNewXML</a></li>
<li><a href="#8_2_29">mxmlRelease</a></li>
<li><a href="#mxmlRemove">mxmlRemove</a></li>
<li><a href="#8_2_31">mxmlRetain</a></li>
<li><a href="#8_2_32">mxmlSAXLoadFd</a></li>
<li><a href="#8_2_33">mxmlSAXLoadFile</a></li>
<li><a href="#8_2_34">mxmlSAXLoadString</a></li>
<li><a href="#mxmlSaveAllocString">mxmlSaveAllocString</a></li>
<li><a href="#mxmlSaveFd">mxmlSaveFd</a></li>
<li><a href="#mxmlSaveFile">mxmlSaveFile</a></li>
<li><a href="#mxmlSaveString">mxmlSaveString</a></li>
<li><a href="#8_2_39">mxmlSetCDATA</a></li>
<li><a href="#8_2_40">mxmlSetCustom</a></li>
<li><a href="#mxmlSetCustomHandlers">mxmlSetCustomHandlers</a></li>
<li><a href="#mxmlSetElement">mxmlSetElement</a></li>
<li><a href="#mxmlSetErrorCallback">mxmlSetErrorCallback</a></li>
<li><a href="#mxmlSetInteger">mxmlSetInteger</a></li>
<li><a href="#mxmlSetOpaque">mxmlSetOpaque</a></li>
<li><a href="#mxmlSetReal">mxmlSetReal</a></li>
<li><a href="#mxmlSetText">mxmlSetText</a></li>
<li><a href="#mxmlSetTextf">mxmlSetTextf</a></li>
<li><a href="#8_2_49">mxmlSetWrapMargin</a></li>
<li><a href="#mxmlWalkNext">mxmlWalkNext</a></li>
<li><a href="#mxmlWalkPrev">mxmlWalkPrev</a></li>
</ul>
</li>
<li><a href="#TYPES">类型定义(typedef)</a>
<ul>
<li><a href="#mxml_attr_t">mxml_attr_t</a></li>
<li><a href="#mxml_custom_destroy_cb_t">mxml_custom_destroy_cb_t</a></li>
<li><a href="#mxml_custom_load_cb_t">mxml_custom_load_cb_t</a></li>
<li><a href="#mxml_custom_save_cb_t">mxml_custom_save_cb_t</a></li>
<li><a href="#8_3_5">mxml_custom_t</a></li>
<li><a href="#mxml_element_t">mxml_element_t</a></li>
<li><a href="#mxml_error_cb_t">mxml_error_cb_t</a></li>
<li><a href="#mxml_index_t">mxml_index_t</a></li>
<li><a href="#mxml_load_cb_t">mxml_load_cb_t</a></li>
<li><a href="#mxml_node_t">mxml_node_t</a></li>
<li><a href="#mxml_save_cb_t">mxml_save_cb_t</a></li>
<li><a href="#mxml_sax_cb_t">mxml_sax_cb_t</a></li>
<li><a href="#mxml_sax_event_t">mxml_sax_event_t</a></li>
<li><a href="#mxml_text_t">mxml_text_t</a></li>
<li><a href="#mxml_value_t">mxml_value_t</a></li>
</ul>
</li>
<li><a href="#STRUCTURES">结构(struct)</a>
<ul>
<li><a href="#mxml_attr_s">mxml_attr_s</a></li>
<li><a href="#8_4_2">mxml_custom_s</a></li>
<li><a href="#mxml_element_s">mxml_element_s</a></li>
<li><a href="#mxml_index_s">mxml_index_s</a></li>
<li><a href="#mxml_node_s">mxml_node_s</a></li>
<li><a href="#mxml_text_s">mxml_text_s</a></li>
</ul>
</li>
<li><a href="#UNIONS">联合(union)</a>
<ul>
<li><a href="#mxml_value_u">mxml_value_u</a></li>
</ul>
</li>
<li><a href="#ENUMERATIONS">Constants</a>
<ul>
<li><a href="#mxml_sax_event_e">mxml_sax_event_e</a></li>
<li><a href="#mxml_type_e">mxml_type_e</a></li>
</ul>
</li>
</ul>
<b><a href="#SCHEMA">XML方案 (用于自动化文档生成工具 mxmldoc)</a></b>
<ul></ul>
<hr noshade="noshade">
<h1 align="right"><a name="INTRO"><img alt="0" src="minixml-cn_files/0.gif" align="right" height="100" hspace="10" width="100"></a>序言</h1>
<p>这份程序员参考手册描述了 Mini-XML 2.5版本, 一个小型的 XML 解析库,使用它可以使你的C或者C++应用程序方便的进行XML数据文件的读写
 </p>
<p>Mini-XML 最初是为了<a href="http://gutenprint.sf.net/">
Gutenprint</a> 项目而开发,目的是为了替换既大又笨重的<tt>
libxml2</tt> 库, 想要实现一个小型且易于使用的一些东西. 它开始于2003年6月的一个早晨,当时罗伯特发表了下面几句话到开发者列表:
    </p>
<blockquote><em>"这真是糟糕,我们需要libxml2,但反复看来,我们的XML解析器仅需要我们可以操作的一小部分。" </em></blockquote>
<p>我做了以下回复:</p>
<blockquote><em>"考虑到你使用XML仅在一个有限的范围中,那么只使用几百行代码来编写一个微型XML (mini-XML) API,应该是很简单的。"</em></blockquote>
<p>我接受了这个挑战,用了两天的时间进行疯狂的编码,并且公开发布了第一个mini-XML版本,总共是696行代码。然后,罗伯特迅速把mini-XML整合到 Gutenprint 中,并且移除了libxml2库</p>
<p>感谢很多不同的开发者给我的回馈和支持, 从那以后,Mini-XML逐渐发展为一个提供更多完整的XML实现,当前已经高达3441行代码,但已经可以和103893行代码的libxml2 2.6.9版本相比较了。
</p>
<div class="zf">译者:仅用了两天时间,作者真是大牛啊!我较喜欢Mini-XML,我也用过TinyXML,libexpat,libxml2等解析器,相比之下Mini-XML实现了一个非常简洁且功能适用的解析器,很适合我的需求:DOM型解析器、解析小型的XML文件,不进行错误恢复及校验,简单易用,且使用纯ANSI-C实现,方便移植到嵌入系统中。评价:很好很强大,而且很简单。Z.F</div>
<p>除了Gutenprint ,mini-XML当前已经应用于以下的项目/应用软件:</p>
<ul>
<li><a href="http://www.cups.org/">Common UNIX Printing System</a></li>
<li><a href="http://www.cups.org/ddk/">CUPS Driver Development Kit</a></li>
<li><a href="http://zynaddsubfx.sourceforge.net/">ZynAddSubFX</a></li>
</ul>
<p>
如果您希望将您的项目添加到此列表或者从此列表中删除,或者如果您有任何意见和想法,或者想要发布关于使用mini-XML的经验,请给我发电子邮件( mxml@easysw.com
</p>
<h2><a name="1_1">本文档组织结构</a></h2>
<p>本手册由以下章节和附录组成:</p>
<ul>
<li>第一章, "<a href="#INSTALL">构建,安装,以及打包Mini-XML</a>", 关于mini-XML在编译、安装以及打包方面的说明.</li>
<li>第二章, "<a href="#BASICS">Mini-XML 入门</a>",如何在你的应用程序中使用mini-XML.
</li>
<li>第三章, "<a href="#ADVANCED">更多的 Mini-XML 编程技术</a>展示了使用mini-XML库的更多的方法。
</li>
<li>第四章, "<a href="#MXMLDOC">使用 mxmldoc 工具</a>",
 描述如何使用<tt>mxmldoc(1)</tt> 程序来生成文档.</li>
<li>附录 A, "<a href="#LICENSE">Mini-XML 许可信息 </a>",使用和发布mini-XML的条款及条件。</li>
<li>附录 B, "<a href="#RELNOTES">发行说明</a>", 列出了每次mini-XML发布版本的改变信息.</li>
<li>附录 C, "<a href="#REFERENCE">库参考手册</a>", 包含了关于mini-XML的完整参考信息,使用 <tt>mxmldoc</tt>生成.</li>
<li>附录 D, "<a href="#SCHEMA">XML方案</a>", 显示了 <tt>mxmldoc</tt> 生成XML文件时使用的 XML 方案.</li>
</ul>

<!-- NEED 10 -->
<h2><a name="1_2">词法约定 </a></h2>
<p>在这篇手册中使用了一些字体和风格的约定.下面是一些例子含义和使用说明:</p>
<dl>
<dt><code>lpstat</code>
<br> <code>lpstat(1)</code></dt>
<dd>命令名称;如果在一章中第一次提及这个系统命令或者函数,则后面跟随手册页编号。<div class="zf">译者:上面指Linux 的manpages 手册,使用man命令查看。Z.F</div>
<br>
<br></dd>
<dt><var>/var</var>
<br><var> /usr/share/cups/data/testprint.ps</var></dt>
<dd>文件或者目录.
<br>
<br></dd>
<dt><tt>Request ID is Printer-123</tt></dt>
<dd>屏幕输出.
<br>
<br></dd>
<dt><kbd>lp -d printer filename ENTER</kbd></dt>
<dd>用户输入的文字,特殊键如<kbd>ENTER</kbd> 总是使用大写.
<br>
<br></dd>
<dt>12.3</dt>
<dd>文本中的数字,使用(.)来表示小数点.
<br>
<br></dd>
</dl>

<!-- NEED 10 -->
<h2><a name="1_3">缩略词</a></h2>
<p>下面是在本手册中使用的缩略词:</p>
<dl>
<dt>Gb</dt>
<dd>GB, 即 1073741824 字节,1*1024*1024*1024 字节
<br>
<br></dd>
<dt>kb</dt>
<dd> 即 1024 字节,1*1024 字节
<br>
<br></dd>
<dt>Mb</dt>
<dd>兆, or 1048576 bytes,1*1024*1024 字节
<br>
<br></dd>
<dt>UTF-8, UTF-16</dt>
<dd>统一的字符编码标准, 8-位 或 16-位
<br>
<br></dd>
<dt>W3C</dt>
<dd>万维网联盟
<br>
<br></dd>
<dt>XML</dt>
<dd>可扩展标记语言
<br>
<br></dd>
</dl>

<!-- NEED 12 -->
<h2><a name="1_4">其他参考</a></h2>
<dl>
<dt>The Unicode Standard, Version 4.0, Addison-Wesley, ISBN
 0-321-18578-1</dt>
<dd>定义了用于XML的Unicode字符集.
<br>
<br></dd>
<dt><a href="http://www.w3.org/TR/2004/REC-xml-20040204/">Extensible
 Markup Language (XML) 1.0 (Third Edition)</a></dt>
<dd>W3C制定的XML标准.
<br>
<br></dd>
</dl>

<!-- NEED 6 -->
<h2><a name="1_5">法律资料</a></h2>
<p>The Mini-XML library is copyright 2003-2008 by Michael Sweet.</p>
<p>This library is free software; you can redistribute it and/or modify
 it under the terms of the <a href="#LICENSE">GNU Library General Public
 License</a> as published by the Free Software Foundation; either
 version 2 of the License, or (at your option) any later version.</p>
<p>This library is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Library General Public License for more details.</p>
<hr noshade="noshade">
<h1 align="right"><a name="INSTALL"><img alt="1" src="minixml-cn_files/1.gif" align="right" height="100" hspace="10" width="100"></a>构建,安装,以及打包Mini-XML </h1>
<p>这一章描述了如何在你的系统上使用源码包构建,安装以及打包Mini-XML,你将需要一个ANSI/ISO-C兼容的C编译器来构建Mini-XML,GCC可以工作,这也是大多数厂家的C编译器。如果你需要在Windows平台上构建, 我们建议使用Virtual C++环境和解决方案文件.对于其他的操作系统,你在C编译器之外需要一个POSIX兼容的shell和<tt>make</tt>程序.
.</p>
<h2><a name="2_1">编译 Mini-XML</a></h2>
<p>Mini-XML 同时具备基于 autoconf的配置脚本和Virtual C++的解决方案,可以用来编译库和关联的其他工具.</p>
<h3><a name="2_1_1">使用 Visual C++ 编译</a></h3>
<p>打开在目录<var> vcnet</var> 下的<var> mxml.sln</var> 解决方案.
 选择需要构建的配置,"Debug" (缺省选项) 或者
 "Release", 并且 从<var>
 Build</var> 菜单中选择<var> Build Solution</var>项.</p>
<h3><a name="2_1_2">使用命令行工具编译</a></h3>
<p>在你的系统上键入下面的命令来配置Mini-XML源代码:</p>
<pre>    <kbd>./configure ENTER</kbd>
</pre>
<p>缺省的安装前缀是<var> /usr/local</var>, 这可以被覆盖使用 <kbd>--prefix</kbd> 选项:</p>
<pre>    <kbd>./configure --prefix=/foo ENTER</kbd>
</pre>
<p>其他配置选项可以使用命令<kbd>--help</kbd>
 选项进行查看:</p>
<pre>    <kbd>./configure --help ENTER</kbd>
</pre>
<p>当你配置完毕,使用<tt>make(1)</tt>程序来构建并且运行测试程序来校验是否工作正常,如下:
</p>
<pre>    <kbd>make ENTER</kbd>
</pre>
<h2><a name="2_2">安装 Mini-XML</a></h2>
<p>如果你使用 Visual C++, 分别拷贝<var> mxml.lib</var> 和 <var>
 mxml.h</var> 文件到 Visual C++<var> lib</var> 和<var> include<var>
 目录.</var></var></p>
<p>否则,使用<tt>make</tt> 命令和<kbd>install</kbd>参数来安装Mini-XML到配置的目录中:</p>
<pre>    <kbd>make install ENTER</kbd>
</pre>
<h2><a name="2_3">创建 Mini-XML 包</a></h2>
<p>Mini-XML 包含两个文件可以被用来创建二进制发行包.第一个文件是<var> mxml.spec</var> 可以被使用通过<tt>
rpmbuild(8)</tt> 软件来创建Red Hat 包管理器("RPM")的发行包,通常用于Linux平台. <tt>rpmbuild</tt>
 可以自己进行软件编译, 你可以为它提供一个Mini-XML 的tar文件来编译整个包,使用以下命令:</p>
<pre>    <kbd>rpmbuild -ta mxml-<i>version</i>.tar.gz ENTER</kbd>
</pre>
<p>第二个文件是<var> mxml.list</var>被用于<tt>
epm(1)</tt> 程序创建不同格式的软件包.
<tt>epm</tt> 程序可以从以下网址获得:</p>
<pre>    <a href="http://www.easysw.com/epm/">http://www.easysw.com/epm/</a>
</pre>
<p>使用<tt>make</tt> 命令通过 <kbd>epm</kbd> 目标 来构建一个针对你的系统的便携的本地包:</p>
<pre>    <kbd>make epm ENTER</kbd>
</pre>
<p>为了你方便,这些包保存在子目录<var> dist</var> 中.便携包利用脚本和tar文件安装软件到目标系统中.在展开包文件后,使用<var> mxml.install</var>脚本来安装这个软件.</p>
<p>这些本地包可以是本地操作系统的原生格式:红帽Linux 的RPM , Debian Linux的DPKG, Solaris的PKG, 等等.使用相应的命令来安装这些原生包.</p>
<hr noshade="noshade">
<h1 align="right"><a name="BASICS"><img alt="2" src="minixml-cn_files/2.gif" align="right" height="100" hspace="10" width="100"></a>Mini-XML 入门</h1>
<p>这一章描述了如何写一个程序使用Mini-XML来访问XML文件中的数据.Mini-XML提供了以下功能:</p>
<ul>
<li>在内存中创建和管理XML文档的函数.</li>
<li>读UTF-8和UTF-16 编码的XML文件和字符串.</li>
<li>写UTF-8 编码的XML文件和字符串.</li>
<li>支持任意的元素名称,属性以及属性值,没有任何其他限制,仅受限于有效内存.</li>
<li>支持整形、浮点、自定义("CDATA")和文本数据类型在"叶"节点.</li>
<li>提供"查找"、"索引"、以及"步进"函数可以很简单的访问XML文档中的数据.</li>
</ul>
<p>Mini-XML 不进行基于"XML方案(SCHEMA)"文件或者其他内容源定义信息的校验和其他类型的处理 ,也不支持其他组织所要求的XML规范.</p>
<h2><a name="3_1">基础知识</a></h2>
<p>Mini-XML 提供的一个你需要包含的头文件:</p>
<pre>    #include &lt;mxml.h&gt;
</pre>
<p>把Mini-XML库连接到你的应用程序使用<kbd>
-lmxml</kbd> 选项:</p>
<pre>    <kbd>gcc -o myprogram myprogram.c -lmxml ENTER</kbd>
</pre>
<p>如果你已经安装<tt>pkg-config(1)</tt> 软件, 你可以使用它来为你的安装确定适当的编译和连接选项:</p>
<pre>    <kbd>pkg-config --cflags mxml ENTER</kbd>
    <kbd>pkg-config --libs mxml ENTER</kbd>
</pre>
<h2><a name="3_2">节点</a></h2>
<p>每一块XML文件中的信息片断(元素、文本、数字)是一个存储在内存中的"节点(nodes)"
 .节点使用<a href="#mxml_node_t">
<tt>mxml_node_t</tt></a> 结构进行定义. 它的<a href="#mxml_type_t"><tt>type</tt>
</a> 成员变量定义了节点类型(element, integer, opaque, real, or
 text) 决定了需要从联合(union)类型的成员变量<a href="#mxml_value_t">
<tt>value</tt></a> 中获取的值.</p>

<!-- NEED 10 -->
<center>
<table summary="Mini-XML Node Value Members" border="1" cellpadding="5" cellspacing="0" width="80%"><caption align="bottom"><i> 表 2-1: Mini-XML 节点值的成员变量
 </i></caption>
<tbody><tr bgcolor="#cccccc"><th>值</th><th>类型</th><th>节点成员</th></tr>
<tr><td>用户定义</td><td><tt>void *</tt></td><td><tt>
node-&gt;value.custom.data</tt></td></tr>
<tr><td>XML元素</td><td><tt>char *</tt></td><td><tt>
node-&gt;value.element.name</tt></td></tr>
<tr><td>整数</td><td><tt>int</tt></td><td><tt>node-&gt;value.integer</tt>
</td></tr>
<tr><td>不透明字符串</td><td><tt>char *</tt></td><td><tt>
node-&gt;value.opaque</tt></td></tr>
<tr><td>浮点数</td><td><tt>double</tt></td><td><tt>node-&gt;value.real</tt></td>
</tr>
<tr><td>文本</td><td><tt>char *</tt></td><td><tt>node-&gt;value.text.string</tt>
</td></tr>
</tbody></table>
</center>
<div class="zf">译者:节点类型定义枚举参见:<a href="#mxml_type_e">mxml_type_e</a>。Mini-XML中的节点类型定义和其他有些解析器有些不同,其中整数、浮点、和文本节点是指在一个XML元素中一系列的使用空格作为分割的值,每个元素可以拥有多个以上节点,并可以选择使用空格分开,如:&lt;abc&gt;aa bb cc&lt;/abc&gt;,Mini-MXML在使用参数:MXML_TEXT_CALLBACK进行载入时,将在abc元素下面生成3个text类型的子节点。在创建时也可以使用同样的方式创建节点。整数和浮点也是同样方式,但如果转换失败则MiniXML报错。而不透明字符串类型(OPAQUE)则不进行字符串分割,在载入时需要使用MXML_OPAQUE_CALLBACK参数,将所有字符串形成一个子节点。详情见:<a href="#ADVANCED">使用加载回调函数</a>。 Z.F</div>

<p>每一个节点总是有一个成员变量:<tt>user_data</tt> 可以允许你为每一个节点关联你需要的应用数据.</p>
<p>新的节点可以使用以下函数进行创建 <a href="#mxmlNewElement"><tt>
mxmlNewElement</tt></a>, <a href="#mxmlNewInteger"><tt>mxmlNewInteger</tt>
</a>, <a href="#mxmlNewOpaque"><tt>mxmlNewOpaque</tt></a>, <a href="#mxmlNewReal">
<tt>mxmlNewReal</tt></a>, <a href="#mxmlNewText"><tt>mxmlNewText</tt></a>
 <a href="#mxmlNewTextf"><tt>mxmlNewTextf</tt></a> <a href="#mxmlNewXML">
<tt>mxmlNewXML</tt></a> . 只有 elements 可以拥有子节点,顶级节点必须是一个 element , 通常是<tt>&lt;?xml
 version="1.0"?&gt;</tt> 使用<tt>mxmlNewXML()</tt>函数创建的节点.</p>
<p>每个节点都有一些关联节点的指针,上(<tt>parent</tt>), 下(<tt>
child</tt>), 左(<tt>prev</tt>), and 右(<tt>next</tt>) 相对应于当前节点. 如果你有一个XML文件如下所示:</p>
<pre>    &lt;?xml version="1.0"?&gt;
    &lt;data&gt;
        &lt;node&gt;val1&lt;/node&gt;
        &lt;node&gt;val2&lt;/node&gt;
        &lt;node&gt;val3&lt;/node&gt;
        &lt;group&gt;
            &lt;node&gt;val4&lt;/node&gt;
            &lt;node&gt;val5&lt;/node&gt;
            &lt;node&gt;val6&lt;/node&gt;
        &lt;/group&gt;
        &lt;node&gt;val7&lt;/node&gt;
        &lt;node&gt;val8&lt;/node&gt;
    &lt;/data&gt;
</pre>
<p>那么在内存中的文件节点树看上去如下所示:</p>
<pre>    ?xml
      |
    data
      |
    node - node - node - group - node - node
      |      |      |      |       |      |
    val1   val2   val3     |     val7   val8
                           |
                         node - node - node
                           |      |      |
                         val4   val5   val6
</pre>
<p>这里"-"指向下一个节点,"|"指向第一个子节点。</p>
<p>当你使用完毕这些XML数据后,使用函数<a href="#mxmlDelete"><tt>
mxmlDelete</tt></a> 来释放指定节点或者整个XML树节点和它下面所有子节点的内存:</p>
<pre>    mxmlDelete(tree);
</pre>

<!-- NEW PAGE -->
<h2><a name="3_3">创建 XML 文档</a></h2>
<p>你可以在内存中创建和更新XML文档,使用<tt>
mxmlNew</tt> 一系列函数. 下面的代码将创建上一章描述的XML文档:</p>
<pre>    mxml_node_t *xml;    /* &lt;?xml ... ?&gt; */
    mxml_node_t *data;   /* &lt;data&gt; */
    mxml_node_t *node;   /* &lt;node&gt; */
    mxml_node_t *group;  /* &lt;group&gt; */

    xml = mxmlNewXML("1.0");

    data = mxmlNewElement(xml, "data");

        node = mxmlNewElement(data, "node");
        mxmlNewText(node, 0, "val1");
        node = mxmlNewElement(data, "node");
        mxmlNewText(node, 0, "val2");
        node = mxmlNewElement(data, "node");
        mxmlNewText(node, 0, "val3");

        group = mxmlNewElement(data, "group");

            node = mxmlNewElement(group, "node");
            mxmlNewText(node, 0, "val4");
            node = mxmlNewElement(group, "node");
            mxmlNewText(node, 0, "val5");
            node = mxmlNewElement(group, "node");
            mxmlNewText(node, 0, "val6");

        node = mxmlNewElement(data, "node");
        mxmlNewText(node, 0, "val7");
        node = mxmlNewElement(data, "node");
        mxmlNewText(node, 0, "val8");
</pre>
<p>我们首先使用<a href="#mxmlNewXML"><tt>mxmlNewXML</tt></a>函数来创建所有XML文件都需要的标头 <tt>&lt;?xml version="1.0"?&gt;</tt>
 :</p>
<pre>    xml = mxmlNewXML("1.0");
</pre>
<p>然后我们使用<a href="#mxmlNewElement"><tt>mxmlNewElement</tt></a>函数来创建本文件使用的<tt>&lt;data&gt;</tt>节点.第一个参数指定了父节点(<tt>xml</tt>) ,第二个参数是元素名 (<tt>data</tt>):</p>
<pre>    data = mxmlNewElement(xml, "data");
</pre>
<p>每个在本文件中<tt>&lt;node&gt;...&lt;/node&gt;</tt>之间的部分使用函数<a href="#mxmlNewElement"><tt>
mxmlNewElement</tt></a> 和 <a href="#mxmlNewText"><tt>mxmlNewText</tt></a>来创建. <tt>mxmlNewText</tt> 的第一个参数指定了父节点 (<tt>node</tt>).第二个参数指定了是否在文本之前添加空白字符,在本例中使用0或者false.最后一个参数指定了需要添加的实际文本:</p>
<pre>    node = mxmlNewElement(data, "node");
    mxmlNewText(node, 0, "val1");
</pre>
<p>在内存中的XML结果可以被保存或者进行其他处理,就像一个从磁盘或者字符串中读取的文档一样.</p>

<!-- NEW PAGE -->
<h2><a name="3_4">加载XML</a></h2>
<p>你可以加载一个XML文件使用函数<a href="#mxmlLoadFile"><tt>
mxmlLoadFile</tt></a> :</p>
<pre>    FILE *fp;
    mxml_node_t *tree;

    fp = fopen("filename.xml", "r");
    tree = mxmlLoadFile(NULL, fp,
                        MXML_TEXT_CALLBACK);
    fclose(fp);
</pre>
<p>第一个参数如果有的话则指定了一个存在的XML父节点.一般你将这个参数等于<tt>NULL</tt>,除非你想要连接多个XML源. 如果此参数等于<tt>NULL</tt>,那么指定的XML文件必须是一个完整的XML文档,文档头部要包含<tt>?xml</tt>元素.</p>
<p>第二个参数指定了一个标准的文件流,使用 <tt>fopen()</tt> 或者 <tt>popen()</tt>进行打开. 你也可以使用<tt>stdin</tt>,如果你想要实现一个XML过滤器程序.</p>
<p>第三个参数指定了一个回调函数用于一个新的XML元素节点直接返回的子节点的值类型: <tt>
MXML_CUSTOM</tt>, <tt>MXML_IGNORE</tt>, <tt>MXML_INTEGER</tt>, <tt>
MXML_OPAQUE</tt>, <tt>MXML_REAL</tt>, or <tt>MXML_TEXT</tt>. 加载回调函数的细节在<a href="#LOAD_CALLBACKS">第三章</a>做了详细描述. 示例代码使用 <tt>MXML_TEXT_CALLBACK</tt> 常量指定文档中所有的数据节点都包含使用以空格字符分割的文本的值. 其他标准的回调还有<tt>
MXML_IGNORE_CALLBACK</tt>, <tt>MXML_INTEGER_CALLBACK</tt>, <tt>
MXML_OPAQUE_CALLBACK</tt>, 和<tt>MXML_REAL_CALLBACK</tt>.</p>
<p>函数<a href="#mxmlLoadString"><tt>mxmlLoadString</tt></a> 可以从一个字符串中载入XML节点树:</p>

<!-- NEED 10 -->
<pre>    char buffer[8192];
    mxml_node_t *tree;

    ...
    tree = mxmlLoadString(NULL, buffer,
                          MXML_TEXT_CALLBACK);
</pre>
<p>第一个和第三个参数和<tt>
mxmlLoadFile()</tt>用法一样. 第二个参数指定了指定了字符串或者字符缓冲区用于加载XML,当父节点参数为<tt>NULL</tt>时内容必须为完整的XML文档,包括XML头<tt>?xml</tt>元素.</p>

<!-- NEW PAGE -->
<h2><a name="3_5">保存 XML</a></h2>
<p>你可以保存XML文件使用<a href="#mxmlSaveFile"><tt>
mxmlSaveFile</tt></a> 函数:</p>
<pre>    FILE *fp;
    mxml_node_t *tree;

    fp = fopen("filename.xml", "w");
    mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
    fclose(fp);
</pre>
<p>第一个参数为想要保存的XML节点树,一般应该是一个指向你的XML文档顶级节点<tt>?xml</tt>的节点指针.</p>
<p>第二个单数是一个标准文件流,使用<tt>
fopen()</tt> 或者 <tt>popen()</tt>来打开. 你也可以使用<tt>stdout</tt> 如果你想要实现一个XML过滤器程序.</p>
<p>第三个参数是一个空白回调函数用来控制保存文件时插入的"空白"字符."空白回调"的详细信息参见<a href="#SAVE_CALLBACKS">
第三章</a>. 以上的示例代码使用了<tt>MXML_NO_CALLBACK</tt>常量来指定不需要特别的空白处理.</p>
<p>函数<a href="#mxmlSaveAllocString"><tt>mxmlSaveAllocString</tt></a>,
 和<a href="#mxmlSaveString"><tt>mxmlSaveString</tt></a> 保存XML节点树到一个字符串中:</p>
<pre>    char buffer[8192];
    char *ptr;
    mxml_node_t *tree;

    ...
    mxmlSaveString(tree, buffer, sizeof(buffer),
                   MXML_NO_CALLBACK);

    ...
    ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
</pre>
<p>第一个和最后一个参数的用法和函数<tt>
mxmlSaveFile()</tt>一样. 函数<tt>mxmlSaveString</tt> 给出了一个指针和长度的参数来保存XML文档到一个固定大小的缓冲区中。,
 <tt>mxmlSaveAllocString()</tt> 返回了使用malloc分配的一个字符串缓冲区<tt>malloc()</tt>.</p>
<h3><a name="3_5_1">自动折行控制</a></h3>
<p>当我们保存XML文档时, Mini-XML一般在第75列进行折行,因为这样在终端下最易读. 函数<a href="#mxmlSetWrapMargin">
<tt>mxmlSetWrapMargin</tt></a> 可以覆盖缺省的折行界限:</p>
<pre>    /* 设置自动折行到 132 列*/
    mxmlSetWrapMargin(132);

    /* 取消自动折行*/
    mxmlSetWrapMargin(0);
</pre>

<!-- NEW PAGE-->
<h2><a name="3_6">搜索和遍历节点</a></h2>
<p>函数<a href="#mxmlWalkPrev"><tt>mxmlWalkPrev</tt></a> and <a href="#mxmlWalkNext">
<tt>mxmlWalkNext</tt></a>可以被用来遍历XML节点树:</p>
<pre>    mxml_node_t *node;
   
    node = mxmlWalkPrev(current, tree,
                        MXML_DESCEND);

    node = mxmlWalkNext(current, tree,
                        MXML_DESCEND);
</pre>
<p>另外,你可以搜索一个命名的XML元素/节点,使用函数<a href="#mxmlFindElement">
<tt>mxmlFindElement</tt></a>:</p>
<pre>    mxml_node_t *node;
   
    node = mxmlFindElement(tree, tree, "name",
                           "attr", "value",
                           MXML_DESCEND);
</pre>
<p>参数<tt>name</tt>, <tt>attr</tt>, 和<tt>value</tt> 可以被设置为<tt>NULL</tt>作为全部匹配, e.g.:</p>

<!-- NEED 4 -->
<pre>    /* 搜索第一个 "a" 元素*/
    node = mxmlFindElement(tree, tree, "a",
                           NULL, NULL,
                           MXML_DESCEND);
</pre>

<!-- NEED 5 -->
<pre>    /* 搜索第一个"a" 元素并包含"href"属性*/
    node = mxmlFindElement(tree, tree, "a",
                           "href", NULL,
                           MXML_DESCEND);
</pre>

<!-- NEED 6 -->
<pre>    /* 搜索第一个"a" 元素并且包含"href"属性等于给出的URL */
    node = mxmlFindElement(tree, tree, "a",
                           "href",
                           "http://www.easysw.com/",
                           MXML_DESCEND);
</pre>

<!-- NEED 5 -->
<pre>    /* 搜索第一个包含"src"属性的XML元素*/
    node = mxmlFindElement(tree, tree, NULL,
                           "src", NULL,
                           MXML_DESCEND);
</pre>

<!-- NEED 5 -->
<pre>    /* 搜索第一个包含"src"= "foo.jpg"属性的XML元素 */
    node = mxmlFindElement(tree, tree, NULL,
                           "src", "foo.jpg",
                           MXML_DESCEND);
</pre>
<p>你也可以使用同样的功能进行遍历:</p>
<pre>    mxml_node_t *node;

    for (node = mxmlFindElement(tree, tree,
                                "name",
                                NULL, NULL,
                                MXML_DESCEND);
         node != NULL;
         node = mxmlFindElement(node, tree,
                                "name",
                                NULL, NULL,
                                MXML_DESCEND))
    {
      ... do something ...
    }
</pre>

<!-- NEED 10 -->
<p>参数<tt>MXML_DESCEND</tt>可以是下面三个常量之一:</p>
<ul>
<li><tt>MXML_NO_DESCEND</tt> 含义是不查看任何的子节点在XML元素层次中,仅查看同级的伙伴节点或者父节点直到到达顶级节点或者给出的树的顶级节点.
<p>"group"节点的上一个节点时它左面的"node"子节点,下一个节点是"group"右面的"node"子节点..
<br>
<br></p>
</li>
<li><tt>MXML_DESCEND_FIRST</tt>含义是向下搜索到一个节点的第一个匹配子节点,但不再继续向下搜索。你一般使用于遍历一个父节点的直接的子节点。
,如:在上面的例子中的所有在"?xml"父节点下的所有的"node"和"group"子节点。.
<p>这个模式仅适用于搜索(search)功能,遍历功能(walk)对待它和 <tt>MXML_DESCEND</tt> 一样,因为每次调用都是首次调用。
<br>
<br></p>
</li>
<li><tt>MXML_DESCEND</tt>含义是一直向下直到树的根部. "group"节点的上一个节点将是"val3"节点,下一个节点将是"group"的下面的第一个子节点。
<p>如果你要使用函数<tt>mxmlWalkNext()</tt>从根结点"?xml" 遍历到整个树的结束, 那么这个顺序将如下所示:</p>
<p><tt>?xml data node val1 node val2 node val3 group node val4 node val5
 node val6 node val7 node val8</tt></p>
<p>如果你从"val8"开始并使用函数<tt>mxmlWalkPrev()</tt>进行遍历,
 这个顺序将是反的,结束于"?xml"节点.</p>
</li>
</ul>
<hr noshade="noshade">
<h1 align="right"><a name="ADVANCED"><img alt="3" src="minixml-cn_files/3.gif" align="right" height="100" hspace="10" width="100"></a>更多的 Mini-XML 编程技术</h1>
<p>这一章显示了更多的在你的应用程序中使用Mini-XML的方法。</p>
<h2><a name="LOAD_CALLBACKS">Load Callbacks</a></h2>
<p><a href="#LOAD_XML">第二章</a> 介绍了函数<a href="#mxmlLoadFile">
<tt>mxmlLoadFile()</tt></a> 和<a href="#mxmlLoadString"><tt>
mxmlLoadString()</tt></a> . 这些函数的最后一个参数是一个回调函数,决定了在一个XML文档中每个数据节点的值的类型。</p>
<p>Mini-XML 为简单XML数据文件定义了几个标准的回调函数:</p>
<ul>
<li><tt>MXML_INTEGER_CALLBACK</tt> - 所有的数据节点包含以空格分割的整数。</li>
<li><tt>MXML_OPAQUE_CALLBACK</tt> - 所有的数据节点包含"不透明"字符串(CDATA)。</li>
<li><tt>MXML_REAL_CALLBACK</tt> - 所有的数据节点包含以空格分割的浮点数。</li>
<li><tt>MXML_TEXT_CALLBACK</tt> - 所有的数据节点包含以空格分割的文本字符串。</li>
</ul>
<p>你可以为更复杂的XML文档提供你自己的回调函数。你的回调函数将接收到一个到当前XML元素节点的指针并且必须为这个XML元素节点返回一个直接子节点的值类型: <tt>MXML_INTEGER</tt>, <tt>MXML_OPAQUE</tt>, <tt>
MXML_REAL</tt>, 或<tt>MXML_TEXT</tt>.这个函数在这个XML元素和它的全部属性被读取<i>以后</i>被调用,所以你可以查看这个XML元素的名称、属性以及属性的值来决定适当的返回值类型。 </p>

<!-- NEED 2in -->
<p>下面的回调函数查看一个名称为"type"的属性或者XML元素的名字来决定它的子节点的值类型:</p>
<pre>    mxml_type_t
    type_cb(mxml_node_t *node)
    {
      const char *type;

     /*
      * 你可以查看属性和/或使用XML元素名,所在层次,等等
      */

      type = mxmlElementGetAttr(node, "type");
      if (type == NULL)
 type = node-&gt;value.element.name;

      if (!strcmp(type, "integer"))
 return (MXML_INTEGER);
      else if (!strcmp(type, "opaque"))
 return (MXML_OPAQUE);
      else if (!strcmp(type, "real"))
 return (MXML_REAL);
      else
 return (MXML_TEXT);
    }
</pre>
<p>要使用这个回调函数,只需要在你调用任何加载函数时简单的使用它的名字:</p>
<pre>    FILE *fp;
    mxml_node_t *tree;

    fp = fopen("filename.xml", "r");
    tree = mxmlLoadFile(NULL, fp, <b>type_cb</b>);
    fclose(fp);
</pre>
<h2><a name="SAVE_CALLBACKS">保存回调</a></h2>
<p><a href="#LOAD_XML">第二章</a> 也介绍了<a href="#mxmlSaveFile">
<tt>mxmlSaveFile()</tt></a>, <a href="#mxmlSaveString"><tt>
mxmlSaveString()</tt></a>, 和<a href="#mxmlSaveAllocString"><tt>
mxmlSaveAllocString()</tt></a> 函数。这些函数的最后一个参数是一个回调函数被用来自动在一个XML文档中添加空白字符。</p>
<p>你的回调函数将在每个XML元素被调用四次,传入参数为一个到这个节点的指针和一个"where"的值:<tt>
MXML_WS_BEFORE_OPEN</tt>, <tt>MXML_WS_AFTER_OPEN</tt>, <tt>
MXML_WS_BEFORE_CLOSE</tt>, 或者<tt>MXML_WS_AFTER_CLOSE</tt>。如果不需要插入空白字符这个回调函数将返回 <tt>NULL</tt>,否则返回字符串(空白、跳格、回车和换行)将被插入。</p>
<p>下面的空白回调可以被用来为XHTML输出添加空白字符,来使它在一般的文本编辑器中更加易读:</p>
<pre>    const char *
    whitespace_cb(mxml_node_t *node,
                  int where)
    {
      const char *name;

     /*
      * 我们可以在任何XML元素之前或之后有条件的添加换行。这些是一些常见的HTML元素。
      */

      name = node-&gt;value.element.name;

      if (!strcmp(name, "html") ||
          !strcmp(name, "head") ||
          !strcmp(name, "body") ||
   !strcmp(name, "pre") ||
          !strcmp(name, "p") ||
   !strcmp(name, "h1") ||
          !strcmp(name, "h2") ||
          !strcmp(name, "h3") ||
   !strcmp(name, "h4") ||
          !strcmp(name, "h5") ||
          !strcmp(name, "h6"))
      {
       /*
 * 在打开之前和关闭之后时换行。
 */

 if (where == MXML_WS_BEFORE_OPEN ||
            where == MXML_WS_AFTER_CLOSE)
   return ("/n");
      }
      else if (!strcmp(name, "dl") ||
               !strcmp(name, "ol") ||
               !strcmp(name, "ul"))
      {
       /*
 * 在列表元素前后都添加换行。
 */

 return ("/n");
      }
      else if (!strcmp(name, "dd") ||
               !strcmp(name, "dt") ||
               !strcmp(name, "li"))
      {
       /*
 * 添加一个"跳格"在&lt;li&gt;, * &lt;dd&gt;,
        * 和 &lt;dt&gt;之前, 以及一个换行在他们后面...
 */

 if (where == MXML_WS_BEFORE_OPEN)
   return ("/t");
 else if (where == MXML_WS_AFTER_CLOSE)
   return ("/n");
      }

     /*
      * 如果不需要添加空白字符则返回NULL。
      */

      return (NULL);
    }
</pre>
<p>要使用这些回调函数,只需要在你调用任何保存函数时简单使用它的名字:</p>
<pre>    FILE *fp;
    mxml_node_t *tree;

    fp = fopen("filename.xml", "w");
    mxmlSaveFile(tree, fp, <b>whitespace_cb</b>);
    fclose(fp);
</pre>

<!-- NEED 10 -->
<h2><a name="4_3">用户定义数据类型</a></h2>
<p>Mini-XML 支持通过全局的载入和保存回调函数使用自定义数据类型。 每次只能有一组回调函数被同时激活,然而你的回调函数可以为支持多种所需要的自定义数据类型来保存更多的信息。 节点类型 <tt>MXML_CUSTOM</tt>
 表示一个自定义数据内容的节点。</p>
<p>加载回调接收一个到当前数据节点的指针和一个不透明字符串数据从XML源中并且将字符集转换为UTF-8编码。例如:如果我们想要支持定制的日期/时间类型并且编码为"yyyy-mm-ddThh:mm:ssZ" (ISO 格式), 那么加载回调函数如下所示:</p>
<pre>    typedef struct
    {
      unsigned      year,    /* Year */
                    month,   /* Month */
                    day,     /* Day */
                    hour,    /* Hour */
                    minute,  /* Minute */
                    second;  /* Second */
      time_t        unix;    /* UNIX time */
    } iso_date_time_t;

    int
    load_custom(mxml_node_t *node,
                const char *data)
    {
      iso_date_time_t *dt;
      struct tm tmdata;

     /*
      * 分配数据结构...
      */

      dt = calloc(1, sizeof(iso_date_time_t));

     /*
      * 尝试从数据字符串中读取6个无符号整数..
      */

      if (sscanf(data, "%u-%u-%uT%u:%u:%uZ",
                 &amp;(dt-&gt;year), &amp;(dt-&gt;month),
                 &amp;(dt-&gt;day), &amp;(dt-&gt;hour),
                 &amp;(dt-&gt;minute),
                 &amp;(dt-&gt;second)) != 6)
      {
       /*
        * 如果不能读取到数字,释放分配的结构并返回一个错误...
        */

        free(dt);

        return (-1);
      }

     /*
      * 数据范围检查...
      */

      if (dt-&gt;month &lt;1 || dt-&gt;month &gt; 12 ||
          dt-&gt;day  &lt;1 || dt-&gt;day &gt; 31 ||
          dt-&gt;hour  &lt;0 || dt-&gt;hour &gt; 23 ||
          dt-&gt;minute  &lt;0 || dt-&gt;minute &gt; 59 ||
          dt-&gt;second  &lt;0 || dt-&gt;second &gt; 59)
      {
       /*
        * 如果日期信息超出范围...
        */

        free(dt);

        return (-1);
      }

     /*
      * 转换ISO时间到以秒为单位的UNIX时间...
      */

      tmdata.tm_year = dt-&gt;year - 1900;
      tmdata.tm_mon  = dt-&gt;month - 1;
      tmdata.tm_day  = dt-&gt;day;
      tmdata.tm_hour = dt-&gt;hour;
      tmdata.tm_min  = dt-&gt;minute;
      tmdata.tm_sec  = dt-&gt;second;

      dt-&gt;unix = gmtime(&amp;tmdata);

     /*
      * 设置自定义节点数据指针和销毁函数指针...
      */

      node-&gt;value.custom.data    = dt;
      node-&gt;value.custom.destroy = free;

     /*
      * 返回没有错误...
      */

      return (0);
    }
</pre>
<p>这个函数成功时返回0,当不能正确解码自定义数据或者数据内容错误时返回-1。自定义数据节点包含一个<tt>void</tt> 指针用来保存这个节点已经分配的自定义数据,还有一个指向销毁函数的指针用于当节点被删除时释放自定义数据。</p>
<p>保存回调接收一个节点指针并且返回一个包含自定义数据值的已经分配的字符串。下面的保存回调函数可以被用来保存我们的ISO日期/时间类型:</p>
<pre>    char *
    save_custom(mxml_node_t *node)
    {
      char data[255];
      iso_date_time_t *dt;

      dt = (iso_date_time_t *)node-&gt;custom.data;

      snprintf(data, sizeof(data),
               "%04u-%02u-%02uT%02u:%02u:%02uZ",
               dt-&gt;year, dt-&gt;month, dt-&gt;day,
               dt-&gt;hour, dt-&gt;minute, dt-&gt;second);

      return (strdup(data));
    }
</pre>
<p>你可以注册这些回调函数使用<a href="#mxmlSetCustomHandlers">
<tt>mxmlSetCustomHandlers()</tt></a> 函数:</p>
<pre>    mxmlSetCustomHandlers(<b>load_custom</b>,<b>save_custom</b>);
</pre>

<!-- NEED 20 -->
<h2><a name="4_4">改变节点的值</a></h2>
<p>到现在为止所有的例子集中描述了如何创建和加载新的XML数据节点。然而,许多的应用程序在它们的工作中需要操纵或者改变节点,所以Mini-XML提供了一些函数来安全的改变节点的值并且不会发生内存泄漏。</p>
<p>已有的节点可以被改变通过使用函数<a href="#mxmlSetElement"><tt>
mxmlSetElement()</tt></a>, <a href="#mxmlSetInteger"><tt>
mxmlSetInteger()</tt></a>, <a href="#mxmlSetOpaque"><tt>mxmlSetOpaque()</tt>
</a>, <a href="#mxmlSetReal"><tt>mxmlSetReal()</tt></a>, <a href="#mxmlSetText">
<tt>mxmlSetText()</tt></a>, 和 <a href="#mxmlSetTextf"><tt>
mxmlSetTextf()</tt></a>。例如:使用下面的函数调用可以改变一个文本节点到包含字符串"new"并且具有前导的空白字符:</p>
<pre>    mxml_node_t *node;

    mxmlSetText(node, 1, "new");
</pre>
<h2><a name="4_5">格式化的文本</a></h2>
<p><a href="#mxmlNewTextf"><tt>mxmlNewTextf()</tt></a>和<a href="#mxmlSetTextf">
<tt>mxmlSetTextf()</tt></a> 函数分别是创建和改变文本节点,使用<tt>printf</tt>-风格的格式字符串和参数。例如:使用下面的函数调用来创建一个新的文本节点包含一个构造的文件名:
</p>
<pre>    mxml_node_t *node;

    node = mxmlNewTextf(node, 1, "%s/%s",
                        path, filename);
</pre>
<h2><a name="4_6">索引</a></h2>
<p>Mini-XML 提供了一些函数来管理节点的索引。当前的实现提供了同样的功能就像 <a href="#mxmlFindElement">
<tt>mxmlFindElement()</tt></a>一样。使用索引优势是可以使搜索和枚举XML元素显著加快。唯一不利的是每个索引都是一个关于这个XML文档的静态快照,所以索引不适合当相对于它的搜索操作,XML数据更加频繁更新时的情况。上面的创建一个索引近似相当于遍历这个XML文档树。在索引中的节点被按照XML元素名和它的参数值进行排序。</p>
<p>这些索引被保存在<a href="#mxml_index_t"><tt>mxml_index_t</tt></a>
 结构中。用<a href="#mxmlIndexNew"><tt>mxmlIndexNew()</tt></a>函数可以创建一个新的索引:</p>
<pre>    mxml_node_t *tree;
    mxml_index_t *ind;

    ind = mxmlIndexNew(tree, "element",
                       "attribute");
</pre>
<p>第一个参数是需要进行索引的XML节点树。通常是一个指向<tt>?xml</tt>元素的节点。</p>
<p>第二个参数包含了需要进行索引的XML元素;使用<tt>NULL</tt>值将按照字母顺序索引所有的XML元素节点。</p>
<p>第三个参数包含了需要进行索引的属性;使用<tt>NULL</tt>将使只有XML元素名字被索引。</p>
<p>当索引被建立后,函数<a href="#mxmlIndexEnum"><tt>
mxmlIndexEnum()</tt></a>, <a href="#mxmlIndexFind"><tt>mxmlIndexFind()</tt>
</a>, and <a href="#mxmlIndexReset"><tt>mxmlIndexReset()</tt></a>可以被用来访问索引中的节点。
函数<a href="#mxmlIndexReset">
<tt>mxmlIndexReset()</tt></a>被用来重置在索引中的"当前"节点指针,允许你在同一个索引中进行新的搜索和枚举遍历。典型应用是你将在你调用函数<a href="#mxmlIndexEnum"><tt>mxmlIndexEnum()</tt></a> 和<a href="#mxmlIndexFind">
<tt>mxmlIndexFind()</tt></a>之前调用这个函数。</p>
<p>函数<a href="#mxmlIndexEnum"><tt>mxmlIndexEnum()</tt></a> 用来枚举在索引中的每一个节点,可以在一个循环中使用,如下所示:</p>
<pre>    mxml_node_t *node;

    mxmlIndexReset(ind);

    while ((node = mxmlIndexEnum(ind)) != NULL)
    {
      // do something with node
    }
</pre>
<p>函数<a href="#mxmlIndexFind"><tt>mxmlIndexFind()</tt></a> 定位下一次在索引中出现的XML元素名和属性值。它可以被用于发现在索引中的所有匹配的XML元素,如下所示:</p>
<pre>    mxml_node_t *node;

    mxmlIndexReset(ind);

    while ((node = mxmlIndexFind(ind, "element",
                                 "attr-value"))
                != NULL)
    {
      // do something with node
    }
</pre>
<p>第二和第三个参数分别表示XML元素名和属性值。使用 <tt>NULL</tt>指针用来返回索引中所有的XML元素或者属性。如果XML元素名和属性值同时为<tt>NULL</tt>则相当于调用函数<tt>
mxmlIndexEnum</tt>。</p>
<p>当我们使用完这个索引后,使用函数<a href="#mxmlIndexDelete%28%29">
<tt>mxmlIndexDelete()</tt></a> 来删除它:</p>
<pre>    mxmlIndexDelete(ind);
</pre>
<h2><a name="4_7">SAX (流方式解析) 加载文档</a></h2>
<p>Mini-XML支持一个关于简单XML API (SAX)的实现,以允许你通过节点流的方式加载和处理XML文档。另外允许你处理任何大小的XML文件,Mini-XML的实现也允许你为下一步的处理而只在内存中保留XML文档的一部分。</p>
<p>The <a href="#mxmlSAXLoad"><tt>mxmlSAXLoadFd</tt></a>, <a href="#mxmlSAXLoadFile">
<tt>mxmlSAXLoadFile</tt></a>, 和<a href="#mxmlSAXLoadString"><tt>
mxmlSAXLoadString</tt></a> 函数提供了SAX加载的API。每个函数工作起来就象 <tt>mxmlLoad</tt> 函数一样,但是使用一个回调函数来处理它读到的每一个节点。</p>
<p>回调函数接收到一个节点,一个事件代码和一个你提供的用户数据指针:</p>
<pre>    void
    sax_cb(mxml_node_t *node,
           mxml_sax_event_t event,
           void *data)
    {
      ... do something ...
    }
</pre>
<p>事件(event)将是下面的其中一个:</p>
<ul>
<li><tt>MXML_SAX_CDATA</tt> - CDATA 正在被读取</li>
<li><tt>MXML_SAX_COMMENT</tt> - 一个注释正在被读取</li>
<li><tt>MXML_SAX_DATA</tt> - 数据(custom, integer, opaque, real, or
 text) 正在被读取</li>
<li><tt>MXML_SAX_DIRECTIVE</tt> - 一个处理指令正在被读取</li>
<li><tt>MXML_SAX_ELEMENT_OPEN</tt> - 一个"打开"元素节点正在被读取,如(<tt>
&lt;element&gt;</tt>)</li>
<li><tt>MXML_SAX_ELEMENT_CLOSE</tt> - 一个"关

【上篇】
【下篇】

抱歉!评论已关闭.