QT Dom方式操作XML

简介: 本文提供了读者已知的XML文件语法结构,对xml基础知识不作介绍,仅介绍了QT操作xml的方法之一。

创建项目


  • 创建一个QtDomXmlTest的widget项目。Qt如何创建项目,网上有很多教程,这里就不介绍了。


  • 修改.pro文件,增加xml支持


image.png


读写操作


为了方便管理,这里自己单独创建了一个操作xml的基类,所有的读写接口都在基类里实现,以后也可以扩展。


注意:这里需要包含头文件QtXml


image.png


创建xml文件


  • QDomDocument:doc文档


  • QDomProcessingInstruction:xml文档说明


  • QDomElement:xml元素


/** 
* @funtion   createDomXml 
* @brief      create xml 
* @param    strRoot Root 节点
* @return    no 
*/
bool DomXmlBase::createDomXml(QString strRoot)
{
        QDomDocument doc;
        // 添加处理指令即XML说明
        QDomProcessingInstruction instruction;
        instruction = doc.createProcessingInstruction("xml",           "version=\"1.0\" encoding=\"UTF-8\"");
        doc.appendChild(instruction);
        // 添加根元素
        QDomElement root = doc.createElement(strRoot);
        doc.appendChild(root);
        QFile file(m_strFileName); 
        if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {       
            return false;    
        }    
        QTextStream out(&file);
     // 将文档保存到文件,4为子元素缩进字符数  
     doc.save(out, 4);     
     file.close();     
     return true;
 }


通过doc对象创建一个xml文件同时包含一个根节点stroot。注:这里的m_strFileName是该类的私有变量,通过构造时赋值的


image.png


插入一个元素


/**
 * @funcname  addDomXml
 * @brief     插入一个节点
 * @param     strId 序号
 * @param     strElementListText <元素值>
 * @return    void
 * @example
 *            <Peoples>
 *                  <People Id="001">
 *                      <Name></Name>
 *                      <Age></Age>
 *                      <Gender></Gender>
 *                      <Hobby></Hobby>
 *                      ....
 *                  </People>
 *            </Peoples>
 */
void DomXmlBase::addDomXml(QString strId, QList<QString> strElementListText)
{
    if(strElementListText.isEmpty())
    {
        qDebug() << "strElementListText is empty";
        return;
    }
    /*1. open file*/
    QFile file(m_strFileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return;
    QDomDocument doc;
    if (!doc.setContent(&file))
    {
        qDebug() << "doc.setContent failed";
        file.close();
        return;
    }
    file.close();
    /*2. add element*/
    QDomElement root = doc.documentElement();
    if(m_RootElement.isEmpty())
        return;
    /*root节点下第一元素*/
    QDomElement device = doc.createElement(m_RootElement); 
    /*为节点赋属性*/
    QDomAttr id = doc.createAttribute("Id");
    QList<QDomElement>  domElementList;
    id.setValue(strId);
    device.setAttributeNode(id);
    int count = strElementListText.count();
    int Elementcount = m_ElementList.count();
    if(count != Elementcount)
    {
        qDebug() << "text count != Elementcount";
        QMessageBox::critical(NULL,"注意","text count != Elementcount");
        return ;
    }
    for (int i = 0; i < count; ++i) {
        QString strElementkey = m_ElementList.at(i);
        QString strElementvalue = strElementListText.at(i);
        QDomElement domElement = doc.createElement(strElementkey);
        QDomText text;
        text = doc.createTextNode(strElementvalue);
        domElement.appendChild(text);
        device.appendChild(domElement);
    }
    root.appendChild(device);
    /*3.save xml*/
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        return ;
    }
    QTextStream out(&file);
    doc.save(out, 4);
    file.close();
    qDebug() << "add Element xml";
}


  • m_RootElement:根节点下第一元素


  • m ElementList:m RootElement的所有子元素


  • 这两个值是在父类构造函数调用setXmlElement初始化的,设计这两个成员变量的初衷是为了让这个类适应同类型结构的所有xml,可以任意修改元素标签以及增加元素的个数。


/**
 * @funcname  setXmlElement
 * @brief     设置根元素标签,元素名称,返回根元素下个数。需先调用
 * @param     strRootElement
 * @param     strList
 * @return    count
 */
int DomXmlBase::setXmlElement(QString strRootElement, QList<QString> strList)
{
    m_ElementList = strList;
    m_RootElement = strRootElement;
    return strList.count();
}


具体用法如下:


 void Widget::on_btnAdd_clicked()
{
    DomXmlBase xml("info.xml");
    QList<QString> strList;
    strList << "Name" << "Age" << "Gender" << "Hobby";
    xml.setXmlElement("people",strList);
    QList<QString> strListText;
    strListText << "Tom" << "22" << tr("男") << tr("跑步");
    xml.addDomXml("001",strListText);
}


或者


image.png

image.png


删除一条记录


这里是按进行ID查找的,如果检测到id相同则,删除。


/**
 * @funcname  deleteDomXml
 * @brief     delete a Element
 * @param     strId
 * @return    no
 */
void DomXmlBase::deleteDomXml(QString strId)
{
    QFile file(m_strFileName);
      if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return ;
      QDomDocument doc;
      if (!doc.setContent(&file))
      {
          file.close();
          return ;
      }
      file.close();
      // 以标签名进行查找
      if(m_RootElement.isEmpty())
          return;
      QDomNodeList list = doc.elementsByTagName(m_RootElement);
      for(int i=0; i<list.count(); i++)
      {
          QDomElement e = list.at(i).toElement();
          if(e.attribute("Id") == strId)                  //如果相等测更新或者删除元素值
          {   // 如果元素的“编号”属性值与我们所查的相同
              // 如果是删除操作
              QDomElement root = doc.documentElement();
              // 从根节点上删除该节点
              root.removeChild(list.at(i));
              QFile file(m_strFileName);
              if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
                  return ;
              QTextStream out(&file);
              doc.save(out,4);
              file.close();
              qDebug() << "delete Element xml";
          }
      }
}


修改一条记录


这里是修改全部子元素的记录,基本上和添加相似,主要熟悉一下接口的使用。


/**
 * @funcname  updateDomXml
 * @brief     update Element
 * @param     strId
 * @param     strListText
 * @return    no
 */
void DomXmlBase::updateDomXml(QString strId, QList<QString> strListText)
{
    if(strListText.count()<m_ElementList.count()) {
          QMessageBox::critical(NULL,"注意","strListText个数小于m_ElementList");
          return ;
      }
      QFile file(m_strFileName);
      if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return ;
      QDomDocument doc;
      if (!doc.setContent(&file))
      {
          file.close();
          return ;
      }
      file.close();
      // 以标签名进行查找
      if(m_RootElement.isEmpty())
          return;
      QDomNodeList list = doc.elementsByTagName(m_RootElement);
      for(int i=0; i<list.count(); i++)
      {
          QDomElement e = list.at(i).toElement();
          if(e.attribute("Id") == strId)
          {   // 如果元素的“编号”属性值与我们所查的相同
              QDomNodeList child = list.at(i).childNodes();
              for(int j = 0; j < child.count(); j++)
              {
                  QString strText = child.at(j).toElement().text();
                  QString strSetValue = strListText.at(j);
                  if(strText != strSetValue)
                  {
                      child.at(j).toElement().firstChild().setNodeValue(strSetValue);
                  }
              }
              QFile file(m_strFileName);
              if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
              return ;
              QTextStream out(&file);
              doc.save(out,4);
              file.close();
              qDebug() << "update Element xml";
              break;
          }
      }
}


读一条记录


/**
 * @funcname  readDomXml
 * @brief     根据id获取其下元素值
 * @param     strId
 * @param     strListText output param
 * @return    no
 */
void DomXmlBase::readDomXml(QString strId, QList<QString> &strListText)
{
    QFile file(m_strFileName);
       if(!strListText.isEmpty())
           strListText.clear();
       if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return ;
       QDomDocument doc;
       if (!doc.setContent(&file))
       {
           file.close();
           return ;
       }
       file.close();
       // 以标签名进行查找
       if(m_RootElement.isEmpty()){
           QMessageBox::critical(NULL,"注意","请先设置setXmlElement");
           return;
       }
       QDomNodeList list = doc.elementsByTagName(m_RootElement);
       for(int i=0; i<list.count(); i++)
       {
           QDomElement e = list.at(i).toElement();
           if(e.attribute("Id") == strId)
           {   // 如果元素的“编号”属性值与我们所查的相同
               QDomNodeList child = list.at(i).childNodes();
               for(int j = 0;j < child.count(); j++) {
                   QString strText;
                   strText = child.at(j).toElement().text();
                   strListText.append(strText);
               }
               break;
           }
       }
}


可以看到readDomXml,updateDomXml,deleteDomXml操作基本相似,几个接口输入输出差异也不大,可以继续封装,根据操作进行操作,最小范围内暴露出一些接口。



doXml(QString operate,QString strId,QList<QString> strListText);


总结


本文主要介绍了QT通过dom操作xml,主要是一些二进制代码实现,希望读者能够通过此文,熟悉xml操作,并且可以自行封装自己想要的接口。


不足之处:如果不在父类构造函数初始化setXmlElement,每次创建基类对象后,都需要手动setXmlElement,否则查询时,找不到元素标签。

相关文章
|
27天前
|
JavaScript 前端开发
低效的DOM操作(js的问题)
低效的DOM操作(js的问题)
|
28天前
|
缓存 JavaScript 前端开发
JavaScript中DOM操作:新手常犯错误与避免策略
【4月更文挑战第1天】本文介绍了JavaScript中DOM操作的基础和新手常犯错误,包括频繁查询DOM、不恰当的遍历、滥用innerHTML、忽视异步与DOM状态以及过度同步更新。建议包括缓存DOM引用、注意文本节点、慎用innerHTML以防止XSS、正确处理异步和批量更新。遵循最佳实践,开发者能提升代码质量和应用性能。
24 2
|
2月前
|
XML 存储 JavaScript
DOM 节点遍历:掌握遍历 XML文档结构和内容的技巧
**XML DOM 遍历、操作和导航概述** - 遍历XML节点树用于提取信息,例如,通过JavaScript的DOM API循环`&lt;book&gt;`子节点显示名称和值。 - DOM解析器处理XML文本数据,包括解析字符数据(PCDATA)和识别CDATA段。 - 节点导航涉及`parentNode`、`childNodes`等属性,`get_nextSibling`等辅助函数避免空文本节点。 - `getElementsByTagName`、`getAttribute`和`nodeValue`用于检索元素、属性值和文本。
42 6
DOM 节点遍历:掌握遍历 XML文档结构和内容的技巧
|
2月前
|
XML C# 数据格式
使用C#操作XML文件
使用C#操作XML文件
12 0
|
2月前
|
JavaScript 前端开发
使用jQuery操作DOM元素
使用jQuery操作DOM元素
16 1
|
1天前
|
XML JavaScript 前端开发
XML DOM - 属性和方法
XML DOM 提供编程接口,用属性和方法访问及操作XML节点。通过JavaScript等语言,可利用DOM属性(如nodeName, nodeValue, parentNode, childNodes, attributes)了解和修改节点信息。方法如getElementsByTagName用于查找特定标签元素,appendChild和removeChild则用于添加或移除子节点。
|
1天前
|
JavaScript 前端开发 开发者
【Web 前端】如何操作DOM元素?
【4月更文挑战第22天】【Web 前端】如何操作DOM元素?
|
3天前
|
XML Web App开发 JavaScript
XML DOM 解析器
大多数浏览器内置XML解析器,用于将XML转换为JavaScript可操作的DOM对象。解析器提供遍历、修改XML节点的功能。以下JS代码示例展示了如何加载XML文档:&quot;books.xml&quot;,通过XMLHttpRequest或ActiveXObject发送请求,获取响应并转化为DOM对象。
|
4天前
|
XML 存储 JavaScript
XML DOM 节点
**XML DOM 把文档解析成节点树:** - 文档是个文档节点 - 每个元素是元素节点,如 `&lt;year&gt;` - 文本、属性和注释对应不同节点 - 元素的文本(如 &quot;2005&quot;)存于单独的文本节点 - `&lt;year&gt;` 的值是其包含的文本节点内容
|
6天前
|
JavaScript
js_操作dom(委托和冒泡事件)
js_操作dom(委托和冒泡事件)
8 0

相关课程

更多

推荐镜像

更多