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,否则查询时,找不到元素标签。

相关文章
|
4月前
|
XML JavaScript Java
【JAVA XML 探秘】DOM、SAX、StAX:揭秘 Java 中 XML 解析技术的终极指南!
【8月更文挑战第25天】本文详细探讨了Java中三种主流的XML解析技术:DOM、SAX与StAX。DOM将XML文档转换为树状结构,便于全方位访问和修改;SAX采取事件驱动模式,适用于大型文件的顺序处理;StAX则兼具DOM和SAX的优点,支持流式处理和随机访问。文中提供了每种技术的示例代码,帮助读者理解如何在实际项目中应用这些解析方法。
212 1
|
5月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
所有 modern browsers 支持 W3C DOM 规范, 但仍存在差异, 主要是处理空白和换行的不同。例如, 在 XML 中, Internet Explorer 不会将空白或换行视为文本节点, 而其他浏览器则会。这会导致相同的 XML 文档在 IE 中的子节点数为 4, 而在其他浏览器中为 9:
|
5月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
输出子节点的数量。结果取决于您所使用的浏览器。IE 浏览器会输出 4(提醒 4 个子节点),而其他浏览器会输出 9(提醒 9 个子节点)。
|
5月前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
遍历(Traverse)意味着在节点树中进行循环或移动。
|
5月前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
遍历(Traverse)意味着在节点树中进行循环或移动。
|
5月前
|
XML 存储 JavaScript
XML DOM - 访问节点
通过 DOM, 可全面访问 XML 文档的节点。实现这一目标有 3 种方法: - 使用 `getElementsByTagName()` 方法, - 循环遍历节点树, - 利用节点间关系进行导航。 `getElementsByTagName()` 返回一个 Node List,即一种节点数组形式。示例代码通过 `loadXMLDoc()` 函数加载 &quot;books.xml&quot; 文件到 `xmlDoc` 变量中,并随后在变量 `x` 中保存所需节点信息。
|
5月前
|
XML Web App开发 JavaScript
XML DOM 解析器
大多数浏览器内置了XML解析器,能将XML文档转换为可由JavaScript操作的XML DOM对象。DOM接口允许遍历XML树并支持节点的访问、插入与删除。加载XML文档需先创建XMLHTTP对象,然后打开并发送请求给服务器,最后将响应设置为XML DOM对象以供后续处理。
|
4月前
|
XML 数据格式
Dom4j 保存XML HL7-V3
Dom4j 保存XML HL7-V3
18 0
|
4月前
|
XML 数据格式
dom4j selectNodes 取不到值 因为XML带有命名空间 HL7
dom4j selectNodes 取不到值 因为XML带有命名空间 HL7
81 0
|
5月前
|
XML Web App开发 JavaScript
XML DOM 解析器
大多数浏览器内置了XML解析器,能将XML文档转换为可由JavaScript访问的XML DOM对象。DOM接口提供方法来遍历、访问、插入和删除XML树中的节点。加载XML文档涉及创建XMLHTTP对象,打开并发送请求给服务器,最后将响应设为DOM对象以供操作。