Skip to content

Latest commit

 

History

History
671 lines (494 loc) · 28 KB

File metadata and controls

671 lines (494 loc) · 28 KB

九、XML 解析的简化

XML 是一种称为可扩展标记语言的文件格式的文件扩展名,用于以结构化格式存储信息。XML 格式广泛用于网络。例如,HTML 是用于创建网页的文件格式,并且基于 XML 格式。从微软 Office 2007 开始,微软 Office 使用了基于 XML 的文件格式,如.docx.xlsx.pptx

本章将涵盖以下食谱:

  • 使用流读取器处理 XML 数据
  • 使用流编写器编写 XML 数据
  • 使用 domdocument 类处理 xml 数据
  • 使用 domdocument 类编写 xml 数据
  • 使用谷歌的地理编码应用编程接口

技术要求

本章的技术要求包括 Qt 5.11.2 MinGW 32 位、Qt Creator 4.8.2 和 Windows 10。

本章使用的所有代码可从以下 GitHub 链接下载:https://GitHub . com/PacktPublishing/Qt5-CPP-GUI-Programming-cook book-第二版/树/主/第 09 章

查看以下视频,查看正在运行的代码:http://bit.ly/2ToL7XU

使用流读取器处理 XML 数据

在这个食谱中,我们将学习如何处理从一个 XML 文件中获取的数据,并使用流阅读器提取它。

怎么做…

让我们按照以下步骤创建一个读取和处理 XML 文件的简单程序:

  1. 在您想要的位置创建一个新的 Qt 小部件应用项目。
  2. 打开任意文本编辑器,创建一个如下所示的 XML 文件,然后保存为scene.xml:
<?xml version="1.0" encoding="UTF-8"?>
<scene>
    <object tag="building">
        <name>Library</name>
        <position>120.0,0.0,50.68</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>
  1. 继续编写 XML 代码,如以下代码所示:
    <object tag="building">
        <name>Town Hall</name>
        <position>80.2,0.0,20.5</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>
    <object tag="prop">
        <name>Tree</name>
        <position>10.46,-0.2,80.2</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>
</scene>
  1. 回到 Qt 创建器,打开mainwindow.h。在脚本顶部#include <QMainWindow>后添加以下标题:
#include <QXmlStreamReader>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
  1. 打开mainwindow.ui,从左侧的小部件框中拖动一个按钮到 UI 编辑器中。将按钮的对象名称更改为loadXmlButton,其显示文本更改为Load XML:

  1. 右键单击按钮并选择转到插槽。将弹出一个窗口,显示可供选择的信号列表。
  2. 选择默认的点击()选项,然后按确定按钮。Qt 现在会在你的头文件和源文件中插入一个槽函数,叫做on_loadXmlButton_clicked()
  3. 将以下代码添加到on_loadXmlButton_clicked()功能中:
void MainWindow::on_loadXmlButton_clicked() {
    QXmlStreamReader xml;

    QString filename = QFileDialog::getOpenFileName(this, "Open Xml", ".", "Xml files (*.xml)");
    QFile file(filename);
    if (!file.open(QFile::ReadOnly | QFile::Text))
        qDebug() << "Error loading XML file.";
    xml.setDevice(&file);
  1. 我们继续编写代码。下面的代码循环遍历 XML 文件,并打印出每个属性的名称和值:
    while(!xml.atEnd()) {
        if (xml.isStartElement()) {
            QString name = xml.name().toString();

            if (name == "object") {
                qDebug() << "[Object]=================================";

                for (int i = 0; i < xml.attributes().size(); i++) {
                    qDebug() << xml.attributes().at(i).name() << xml.attributes().at(i).value();
                }
            }
  1. 从 XML 文件中读取元素文本,如以下代码所示:
            if (name == "name" || name == "position" || name == "rotation" || name == "scale") {
                QString text = xml.readElementText();
                qDebug() << name << text;
            }
        }

        if (xml.isEndElement()) {
            QString name = xml.name().toString();

            if (name == "object") {
                qDebug() << "=========================================";
            }
        }
  1. 完成代码前检查错误信息:
        xml.readNext();
    }

    if (xml.hasError()) {
        qDebug() << "Error loading XML:" << xml.errorString();
    }
}
  1. 构建并运行项目,您将看到一个弹出窗口,看起来像您在 s 步骤 4 中创建的窗口:

  1. 点击Load XML按钮,屏幕上会弹出文件选择窗口。选择您在第 2 步中创建的 XML 文件,然后按选择按钮。您应该会在 Qt Creator 的应用输出窗口中看到以下调试文本,这表明程序已经成功地从您刚刚选择的 XML 文件中加载了数据:

它是如何工作的…

在这个例子中,我们试图使用QXmlStreamReader类从一个 XML 文件中提取和处理数据。假设你正在制作一个电脑游戏,你正在使用 XML 文件来存储游戏场景中所有对象的属性。在这种情况下,XML 格式在以结构化方式存储数据方面起着重要作用,这使得提取变得容易。

我们需要将与 XML 相关的类的头部添加到我们的源文件中,在本例中是QXmlStreamReader类。QXmlStreamReader类内置在 Qt 的核心库中,所以不需要包含任何额外的模块,这也意味着它是 Qt 中处理 XML 数据的推荐类。一旦我们点击Load XML按钮,就会调用on_loadXmlButton_clicked()槽;这就是我们编写代码来处理 XML 数据的地方。

我们使用文件对话框来选择我们想要处理的 XML 文件。然后,我们将所选文件的文件名及其路径发送到QFile类,以打开并读取 XML 文件的文本数据。之后,文件的数据被发送到QXmlStreamReader类进行处理。

我们使用while循环来读取整个 XML 文件,并检查流读取器处理的每个元素。我们确定元素是开始元素还是结束元素。如果它是一个 start 元素,我们检查该元素的名称,以确定该元素是否应该包含任何我们需要的数据。

然后,我们以属性或文本的形式提取数据。一个元素可能有不止一个属性,这就是为什么我们必须遍历所有属性并逐个提取它们。

还有更多…

除了网络浏览器之外,许多商业游戏引擎和交互式应用都使用 XML 格式来存储游戏场景、网格和其他产品中使用的资产形式的信息。这是因为与其他文件格式相比,XML 格式提供了许多优势,例如紧凑的文件大小、高灵活性和可扩展性、易于文件恢复以及关系树结构,使其能够用于高效且对性能至关重要的应用,如搜索引擎、智能数据挖掘服务器和科学模拟。

让我们稍微了解一下 XML 文件的格式。我们将使用scene.xml,我们在前面的例子中使用了使用流阅读器处理 XML 数据的方法,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<scene>
    <object tag="building">
        <name>Library</name>
        <position>120.0,0.0,50.68</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>

可以有多个对象标签:

    <object tag="building">
        <name>Town Hall</name>
        <position>80.2,0.0,20.5</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>
    <object tag="prop">
        <name>Tree</name>
        <position>10.46,-0.2,80.2</position>
        <rotation>0.0,0.0,0.0</rotation>
        <scale>1.0,1.0,1.0</scale>
    </object>
</scene>

在 XML 中,标签是一行标记文本,以<符号开始,以>符号结束;<scene>是一个叫场景的标签,<object>是一个叫对象的标签,以此类推。标签有三种风格:

  • 起始标签,例如<scene>
  • 结束标记,例如</scene>
  • 空元素标签,例如<scene />

每当您编写开始标记时,它必须以结束标记结束,否则您的 XML 数据将无效。然而,空元素标记是一个独立的标记,它后面不需要结束标记。

scene.xml文件的顶部,您将看到一个名为xml的标签,它存储了 XML 格式的版本和编码类型,在本例中是 XML 1.0 版本和 UTF-8 (8 位 Unicode)编码。这一行称为 XML 声明,它必须存在于您的一个 XML 文件中才能验证其格式。

之后,您会看到其中存储了属性的标签,例如<object tag="building">。这意味着对象标签包含一个名为标签的属性,它包含一个值,building。您可以在标签中放入任意多的属性,例如<object tag="building" color="red" name="LA Community Hospital" coordinate="34.0191757,-118.2567239">。这些属性中的每一个都存储了不同的数据,可以使用 Qt 轻松检索。

您还可以在开始标记和结束标记之间存储数据;例如<name>Town Hall</name>。然而,这个方法与空元素标签无关,因为它是一个独立的标签,后面没有结束标签。因此,您只能将属性存储在空元素标记中。

To learn more about the XML format, visit http://www.w3schools.com/xml.

使用流编写器编写 XML 数据

由于我们已经在前面的食谱中学习了如何处理从 XML 文件中获得的数据,我们将继续学习如何将数据保存到 XML 文件中。我们将继续前面的例子,并对其进行补充。

怎么做…

我们将通过以下步骤学习如何将数据保存到 XML 文件中:

  1. mainwindow.ui上增加另一个按钮,然后将其对象名设置为saveXmlButton,标签设置为Save XML:

  1. 右键单击按钮并选择转到插槽。将弹出一个窗口,显示可供选择的信号列表。选择单击的()选项,然后单击确定。一个名为on_saveXmlButton_clicked()的信号函数现在将由 Qt 自动添加到您的mainwindow.hmainwindow.cpp文件中:

  1. 将以下代码添加到on_saveXmlButton_clicked()功能中:
QXmlStreamWriter xml;
QString filename = QFileDialog::getSaveFileName(this, "Save Xml", ".", "Xml files (*.xml)");
QFile file(filename);
if (!file.open(QFile::WriteOnly | QFile::Text))
    qDebug() << "Error saving XML file.";
xml.setDevice(&file);
xml.setAutoFormatting(true);
xml.writeStartDocument();
  1. 让我们也写第一个接触元素:
xml.writeStartElement("contact");
xml.writeAttribute("category", "Friend");
xml.writeTextElement("name", "John Doe");
xml.writeTextElement("age", "32");
xml.writeTextElement("address", "114B, 2nd Floor, Sterling Apartment, Morrison Town");
xml.writeTextElement("phone", "0221743566");
xml.writeEndElement();
  1. 按如下方式书写第二个接触元素:
xml.writeStartElement("contact");
xml.writeAttribute("category", "Family");
xml.writeTextElement("name", "Jane Smith");
xml.writeTextElement("age", "24");
xml.writeTextElement("address", "13, Ave Park, Alexandria");
xml.writeTextElement("phone", "0025728396");
xml.writeEndElement();
xml.writeEndDocument();
  1. 构建并运行程序,您应该会在程序用户界面上看到一个附加按钮:

  1. 点击Save XML按钮,屏幕上将出现保存文件对话框。键入所需的文件名,然后单击保存按钮。
  2. 用任何文本编辑器打开刚刚保存的 XML 文件。文件的第一部分应该如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<contact category="Friend">
    <name>John Doe</name>
    <age>32</age>
    <address>114B, 2nd Floor, Sterling Apartment, Morrison Town</address>
    <phone>0221743566</phone>
</contact>
  1. 文件的第二部分应该如下所示:
<contact category="Family">
    <name>Jane Smith</name>
    <age>24</age>
    <address>13, Ave Park, Alexandria</address>
    <phone>0025728396</phone>
</contact>

它是如何工作的…

保存过程类似于上一个示例中的加载 XML 文件。唯一不同的是,我们没有使用QXmlStreamReader类,而是改用了QXmlStreamWriter类。我们仍然使用文件对话框和QFile类来保存 XML 文件。这一次,我们要先把开放模式从QFile::ReadOnly改成QFile::WriteOnly,才能通过QFile班转到流写手。

在我们开始向新的 XML 文件中写入任何数据之前,我们必须将自动格式化设置为 true,否则将没有间距;它还在 XML 文件中添加了新的行和缩进,使其整洁且易于阅读。但是,如果你的意图是让用户更难阅读和编辑,你可以忽略setAutoFormatting()功能。

接下来,通过调用writeStartDocument()开始编写 XML 文件,后面是想要保存到文件中的所有元素,最后我们调用writeEndDocument()函数停止编写。每个元素必须有开始和结束标签,以便阅读过程正常工作。元素的属性将存储在开始标记中,而文本数据将存储在开始标记和结束标记之间。

如果我们正在编写一个包含一组子元素的元素,我们必须在编写子元素之前调用writeStartElement()。保存其所有子元素后调用writeEndElement()以结束标记关闭该组。但是writetextElement()功能会自动为你添加结束标签,所以你不用担心那个。可以调用writeAttribute()函数给元素添加属性。您可以向特定元素添加的属性数量没有限制。

使用 domdocument 类处理 xml 数据

Qt 允许多种解析 XML 数据的方法,包括我们在前面的例子中介绍的通用方法。这次,我们将学习如何使用另一个名为QDomDocument的类从 XML 文件中读取数据。

怎么做…

使用QDomDocument类处理 XML 数据非常简单:

  1. 打开项目(.pro)文件,在coregui后添加xml文本,将 XML 模块添加到项目中,如下代码所示:
QT += core gui xml
  1. 创建一个带有按钮的用户界面,上面写着Load XML:

  1. 右键单击按钮,选择转到插槽…,然后选择单击的()选项。按下确定按钮,Qt 将在你的源代码中添加一个槽函数。
  2. 转到mainwindow.h并添加以下标题,以便我们可以利用这些类:
#include <QDomDocument>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
  1. 转到mainwindow.cpp并将以下代码插入按钮的clicked()插槽功能:
void MainWindow::on_loadXmlButton_clicked() {
    QDomDocument xml;
    QString filename = QFileDialog::getOpenFileName(this, "Open Xml", ".", "Xml files (*.xml)");
    QFile file(filename);
    if (!file.open(QFile::ReadOnly | QFile::Text))
        qDebug() << "Error loading XML file.";
    if (!xml.setContent(&file)) {
        qDebug() << "Error setting content.";
        file.close();
        return;
    }
    file.close();
  1. 我们继续编写代码来加载 XML:
QDomElement element = xml.documentElement();
    QDomNode node = element.firstChild();
    while(!node.isNull()) {
        QDomElement nodeElement = node.toElement();
        if(!nodeElement.isNull()) {
            if (nodeElement.tagName() == "object") {
                qDebug() << "[Object]=================================";
                QDomNode childNode = nodeElement.firstChild();
  1. 前面的代码继续如下:
                while (!childNode.isNull()) {
                    QDomElement childNodeElement = childNode.toElement();
                    QString name = childNodeElement.tagName();
                    if (name=="name" || name=="position" || name=="rotation" || name=="scale") {
                        QString text = childNodeElement.text();
                        qDebug() << name << text;
                    }
                    childNode = childNode.nextSibling();
                }
            }
            qDebug() << "=========================================";
        }
        node = node.nextSibling();
    }
}
  1. 编译并运行程序。点击Load XML按钮,选择第一个例子中使用的 XML 文件。您应该会看到以下输出:

它是如何工作的…

QXmlStreamReader相比,QDomDocument类在加载或保存 XML 数据时就不那么简单了。然而,QDomDocument通过确保每个元素递归地链接到其各自的父元素,就像在树结构中一样,严格地做到了这一点。与QXmlStreamReader不同,QDomDocument允许我们将数据保存到更早创建的元素中,保存在更晚的时间范围内。

由于QDomDocument不是 Qt 核心库的一部分,所以我们必须手动将 XML 模块添加到我们的项目中。否则,我们将无法访问QDomDocument和与其相关的其他类。

首先,我们加载 XML 文件,并将其内容提取到QDomDocument类。然后,我们获得它的文档元素,它充当根文档,并获得它的直接子文档。然后,我们将每个子节点转换为QDomElement并获得它们的标签名。通过检查标签名,我们能够确定我们期望从每个元素中得到的数据类型。

由于这是带有标记名对象的第一层元素,我们不期望从它们那里得到任何数据;我们再次重复 s tep 3 ,但这一次我们将在具有标签名对象的元素上执行,并获得它的所有直接子元素,这意味着文档元素的孙子。

同样,通过检查标签名,我们能够知道我们可以从其子元素中得到什么数据。如果标签名称与我们期望的匹配(在本例中是名称、位置、旋转和缩放),我们可以通过调用QDomElement::text()来获取它的数据。

使用 domdocument 类编写 xml 数据

在这个例子中,我们将学习如何使用QDomDocument类将数据写入一个 XML 文件。我们将继续前面的例子,只是添加更多的代码。

怎么做…

要了解如何使用QDomDocument类将数据保存到一个 XML 文件中,让我们执行以下操作:

  1. 在 UI 中增加第二个按钮,叫做Save XML:

  1. 右键单击Save XML按钮,选择转到插槽。然后,选择单击的()选项,并单击确定。一个新的 clicked()插槽函数将被添加到您的源文件中。
  2. 在按钮的clicked()槽功能中写入以下代码:
void MainWindow::on_saveXmlButton_clicked() {
    QString filename = QFileDialog::getSaveFileName(this, "Save Xml", ".", "Xml files (*.xml)");
    QFile file(filename);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        qDebug() << "Error saving XML file.";
        file.close();
        return;
    }
  1. 前面的代码继续:
    QDomDocument xml("contact");

    // John Doe
    QDomElement root = xml.createElement("contact");
    root.setAttribute("category", "Family");
    xml.appendChild(root);

    QDomElement tagName = xml.createElement("name");
    root.appendChild(tagName);
    QDomText textName = xml.createTextNode("John Doe");
    tagName.appendChild(textName);
  1. 保存ageaddress元素:
    QDomElement tagAge = xml.createElement("age");
    root.appendChild(tagAge);
    QDomText textAge = xml.createTextNode("32");
    tagAge.appendChild(textAge);

    QDomElement tagAddress = xml.createElement("address");
    root.appendChild(tagAddress);
    QDomText textAddress = xml.createTextNode("114B, 2nd Floor, Sterling Apartment, Morrisontown");
    tagAddress.appendChild(textAddress);
  1. 让我们继续phone元素。继续下一个联系人:
    QDomElement tagPhone = xml.createElement("phone");
    root.appendChild(tagPhone);
    QDomText textPhone = xml.createTextNode("0221743566");
    tagPhone.appendChild(textPhone);

    // Jane Smith
    QDomElement root2 = xml.createElement("contact");
    root2.setAttribute("category", "Friend");
    xml.appendChild(root2);
  1. 保存nameage:
    QDomElement tagName2 = xml.createElement("name");
    root2.appendChild(tagName2);
    QDomText textName2 = xml.createTextNode("Jane Smith");
    tagName2.appendChild(textName2);

    QDomElement tagAge2 = xml.createElement("age");
    root2.appendChild(tagAge2);
    QDomText textAge2 = xml.createTextNode("24");
    tagAge2.appendChild(textAge2);
  1. 保存addressphone:
    QDomElement tagAddress2 = xml.createElement("address");
    root2.appendChild(tagAddress2);
    QDomText textAddress2 = xml.createTextNode("13, Ave Park, Alexandria");
    tagAddress2.appendChild(textAddress2);

    QDomElement tagPhone2 = xml.createElement("phone");
    root2.appendChild(tagPhone2);
    QDomText textPhone2 = xml.createTextNode("0025728396");
    tagPhone2.appendChild(textPhone2);
  1. 将所有数据流式传输到 XML 文件中:
    // Save to file
    QTextStream output(&file);
    output << xml.toString();
    file.close();
}
  1. 编译运行程序,点击Save XML按钮。在保存文件对话框中输入所需的文件名,然后单击保存。
  2. 用任何文本编辑器打开保存在 s 步骤 4 中的 XML 文件,您应该会看到如下内容:
<!DOCTYPE contact>
<contact category="Family">
    <name>John Doe</name>
    <age>32</age>
    <address>114B, 2nd Floor, Sterling Apartment, Morrisontown</address>
    <phone>0221743566</phone>
</contact>
  1. 我们还可以看到它下面的第二个触点:
<contact category="Friend">
    <name>Jane Smith</name>
    <age>24</age>
    <address>13, Ave Park, Alexandria</address>
    <phone>0025728396</phone>
</contact>

它是如何工作的…

与前面的例子类似,我们首先启动文件对话框并声明一个QDomDocument对象。然后,我们通过调用QDomDocument::createElement()来创建根元素。从QDomDocument创建的任何元素都不会自动成为它的直接子元素,除非我们将新创建的元素追加为它的子元素。

要创建QDomDocument的子元素,只需将新创建的元素追加到根元素中。通过利用append()功能,我们可以很容易地将 XML 数据排列成树形结构,而不用绕着它打转。这在我看来就是用QDomDocument代替QXmlStreamReader的好处。

然后我们可以通过调用QDomElement::setAttribute()给元素添加属性。我们还可以通过调用QDomDocument::createTextNode()并将其附加到 XML 结构中的任何元素来创建一个文本节点。在我们完成了 XML 数据的结构化之后,我们可以将所有数据以文本的形式输出到QTextStream类,并允许它将数据保存到一个文件中。

使用谷歌的地理编码应用编程接口

在本例中,我们将学习如何使用谷歌的地理编码 API 获取特定位置的完整地址。

怎么做…

让我们按照以下步骤创建一个利用地理编码应用编程接口的程序:

  1. 创建一个新的 Qt 小部件应用项目。
  2. 打开mainwindow.ui并添加几个文本标签、输入字段和一个按钮,使您的用户界面看起来像这样:

  1. 打开您的项目(.pro)文件,并将网络模块添加到您的项目中。您只需在coregui后添加network文本即可,如下代码所示:
QT += core gui network
  1. 打开mainwindow.h并在源代码中添加以下标题:
#include <QMainWindow>:
#include <QDebug>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QXmlStreamReader>
  1. 手动声明一个槽函数并调用它getAddressFinished():
private slots:
    void getAddressFinished(QNetworkReply* reply);
  1. 声明一个名为addressRequest的私有变量:
private:
    QNetworkAccessManager* addressRequest;
  1. 再次打开mainwindow.ui,右键点击获取地址按钮,选择转到插槽。然后选择单击的()选项,并按确定。插槽功能现在将被添加到mainwindow.hmainwindow.cpp源文件中。
  2. 打开mainwindow.cpp,将以下代码添加到类构造函数中:
MainWindow::MainWindow(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::MainWindow) {
    ui->setupUi(this);
 addressRequest = new QNetworkAccessManager();
 connect(addressRequest, &QNetworkAccessManager::finished, this, &MainWindow::getAddressFinished);
}
  1. 将以下代码添加到我们刚刚手动声明的getAddressFinished()槽函数中:
void MainWindow::getAddressFinished(QNetworkReply* reply) {
    QByteArray bytes = reply->readAll();
    //qDebug() << QString::fromUtf8(bytes.data(),
    bytes.size());
    QXmlStreamReader xml;
    xml.addData(bytes);
  1. 继续遍历 XML 文件,获取text元素:
    while(!xml.atEnd()) {
        if (xml.isStartElement()) {
            QString name = xml.name().toString();
            //qDebug() << name;
            if (name == "formatted_address") {
                QString text = xml.readElementText();
                qDebug() << "Address:" << text;
                return;
            }
        }
        xml.readNext();
    }
  1. 检查任何错误文本:
    if (xml.hasError()) {
        qDebug() << "Error loading XML:" <<
        xml.errorString();
        return;
    }
    qDebug() << "No result.";
}
  1. 将以下代码添加到 Qt 创建的clicked()槽函数中:
void MainWindow::on_getAddressButton_clicked() {
    QString latitude = ui->latitude->text();
    QString longitude = ui->longitude->text();
    QNetworkRequest request;
    request.setUrl(QUrl("http://maps.googleapis.com/maps/api/geocode/xml?latlng=" + latitude + "," + longitude + "&key=AIzaSyBhKayXIr2zgMW2olsxtuZ7x2QWyLo1itQ"));
    addressRequest->get(request);
}
  1. 构建并运行程序,您应该能够通过插入经度和纬度值并单击获取地址按钮来获取地址:

  1. 让我们试试经度-73.9780838和纬度40.6712957。单击获取地址按钮,您将在应用输出窗口中看到以下结果:
Address: "180-190 7th Ave, Brooklyn, NY 11215, USA"

它是如何工作的…

我无法确切告诉你谷歌是如何从其后端系统获取地址的,但我可以教你如何使用QNetworkRequest向谷歌请求数据。您所需要做的就是将网络请求的网址设置为我在前面的源代码中使用的网址,并将纬度和经度信息都附加到该网址上。

之后,我们能做的就是等待谷歌 API 服务器的响应。我们需要在向谷歌发送请求时指定 XML 作为所需的格式;否则,它可能会以 JSON 格式返回结果。这可以通过在网络请求 URL 中添加xml关键字来实现,如下图所示:

request.setUrl(QUrl("http://maps.googleapis.com/maps/api/geocode/xml?keylatlng=" + latitude + "," + longitude + "&key=AIzaSyBhKayXIr2zgMW2olsxtuZ7x2QWyLo1itQ"));

当程序收到谷歌的响应时,将调用getAddressFinished()槽函数,我们将能够通过QNetworkReply获取谷歌发送的数据。

谷歌通常以 XML 格式的长文本回复,其中包含大量我们不需要的数据。我们使用QXmlStreamReader类来解析数据,因为在这种情况下,我们不必关心 XML 结构的父子关系。

我们需要的只是存储在 XML 数据的formatted_address元素中的文本。由于formatted_address这个名字的元素不止一个,我们只需要找到第一个,忽略其余的。您也可以通过向谷歌提供地址并从其网络响应中获取位置坐标来实现相反的操作。

还有更多…

谷歌地理编码应用编程接口是谷歌地图应用编程接口网络服务的一部分,为您的地图应用提供地理数据。除了地理编码应用编程接口,您还可以使用它们的位置应用编程接口地理定位应用编程接口时区应用编程接口来实现您想要的结果。

For more information regarding the Google Maps APIs web services, visit https://developers.google.com/maps/web-services.