整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Qt编程进阶(95):使用QXmlStreamRea

Qt编程进阶(95):使用QXmlStreamReader读取XML

、XML是什么?

XML(eXtensible Markup Language,可扩展标记语言)是普遍用于数据交换和数据存储的一种多用途文本文件格式。XML首先是由万维网协会(World Wide Web Consortium,W3C)作为SGML的一个替代品来开发的。它的语法规则与HTML相似,不过XML是一种用于语言分析的语言,它并没有要求专门的标记符,属性或者条目。HTML的XML兼容版称为XHTML。

对于比较流行的SVG(可标量化矢量图形)XML格式,QtSvg模块提供了可用于载入并呈现SVG图像的类。对于使用MathML(数学标记语言)XML格式的绘制文档,可以使用Qt Solutions中的QtMmLWidget。

对于一般的XML数据处理,Qt提供了QtXml模块,这是本文的主题。

二、XML的读取方式

QtXml模块提供了三种截然不同的应用程序编程接口用来读取XML文件:

  • (1)QXmlStreamReader是一个用于读取格式良好的XML文档的快速解析器。
  • (2)DOM(文档对象模型)把XML文档转换为应用程序可以遍历的树形结构。
  • (3)SAX(XML简单应用程序编程接口)通过虚拟函数直接向应用程序报告“解析事件”。

QXmlStreamReader类最快且最容易使用,它同时还提供了与其他Qt兼容的应用程序编程接口。它很适用于编写单通解析器。DOM的主要优点是它能以任意顺序遍历XML文档的树形表示,同时可以实现多通解析算法。有一些应用程序甚至使用DOM树作为它们的基本数据结构。SAX则因为一些历史原因而被得以沿用至今,使用QXmlStreamReader通常会有更加简单高效的编码。

使用QXmlStreamReader是在Qt中读取XML文档的最快且最简单的方式。因为解析器的工作能力是逐渐递增的,所以它尤其适用于诸如查找XML文档中一个给定的标记符号出现的次数、读取内存容纳不了的特大文件、组装定制的数据结构以反映XML文档的内容等。

QXmlStreamReader解析器根据下图中所列出的记号工作。每次只要调用readNext()函数,下一个记号就会被读取并变成当前的记号。当前记号的属性取决于记号的类型,可以使用表格中列出的getter函数读取当前记号。

考虑如下的XML文档:

<doc>
<quote>Einmal ist keinmal</quote>
</doc>

如果解析这个文档,则readNext()每调用一次都将生成一个新记号,若使用getter函数还会获得额外的信息;

StartDocument
StartElement (name()=="doc")
StartElement (name()=="quote")
Characters (text()==" Einmal ist keinmal")
EndElement (name()=="quote")
EndElement (name()=="doc")
EndDocument

每次调用readNext()后,都可以使用isStartElement(),isCharacters()及类似的函数或者仅仅用state()来测试当前记号的类型。

三、QXmlStreamReader读取XML实例

下面将查看一个实例,它告诉我们如何使用QXmlStreamReader解析一个专门的XML文件格式(图1的bookindex.xml)并在QTreeWidget中显示其内容。所解析的是那种具有书刊索引目录且包含索引条目和子条目的文档格式。下图是在QTreeWidget中显示的书刊索引文件。

1、QtXml库

在这个应用程序中使用的QXmlStreamReader类是QtXml库中的一部分。必须在.pro文件中加入如下一行命令:

QT +=xml

在代码中添加头文件:

#include <QXmlStreamReader>

2、主程序代码

首先查看应用程序中XML阅读器在上下文中是如何使用的。

Widget::Widget(QWidget *parent)
: QWidget(parent), ui(new Ui::Widget)
{
  ui->setupUi(this);
  ui->treeWidget->setColumnCount(2);
  QStringList header;
  header<<"Terms"<<"Pages";
  ui->treeWidget->setHeaderLabels(header);
  XmlStreamReader reader(ui->treeWidget);
  reader.readFile("bookindex.xml");
}

在图中显示的应用程序界面中创建一个QTreeWidget。之后,这个应用程序创建一个XmlStreamReader,并将树形窗口部件值传递给该XmlStreamReader,并要求它解析所指定的一个文件。

3、XmlStreamReader类的定义

然后,我们将查看阅读器的实现代码。

class XmlStreamReader
{
public:
  XmlStreamReader(QTreeWidget *tree);
  bool readFile(const QString &fileName);
private:
  void readBookindexElement();
  void readEntryElement(QTreeWidgetItem *parent);
  void readPageElement(QTreeWidgetItem *parent);
  void skipUnknownElement();
  QTreeWidget *treeWidget;
  QXmlStreamReader reader;
};

XmlStreamReader类提供了两个公共函数:构造函数和readFile()函数。这个类使用QXmlStreamReader解析XML文件,并配合QTreeWidget窗口以反映其读入的XML数据。通过使用向下递归的方法来实现这一解析过程。

  • readBookindexElement()解析一个含有0或0个以上<entry>元素的<bookindex>…</bookindex>元素。
  • readEntryElemen()解析一个含有0或0个以上<page>元素的<entry>…</entry>元素,以及嵌套任意层次的含有0或0个以上<entry>元素。
  • readPageElement()解析一个<page> …</page>元素。
  • skipUnknownElement()跳过不能识别的元素。

4、XmlStreamReader类的实现

现在看看XmlStreamReader类的实现,由构造函数开始。

XmlStreamReader::XmlStreamReader(QTreeWidget *tree)
{
	treeWidget=tree;
}

构造函数只是用来建立阅读器将使用的那个QTreeWidget。所有的操作都将在readFile()函数中完成(由main()函数调用)。

bool XmlStreamReader::readFile(const QString &fileName)
{
  QFile file(fileName);
  if(!file.open(QFile::ReadOnly | QFile::Text)){ // (a)
    std::cerr<<"Error: Cannot read file "<<qPrintable(fileName)
    	<<": "<<qPrintable(file.errorString())<<std::endl;
    return false;
  }
  reader.setDevice(&file);
  reader.readNext(); // (b)
  while (!reader.atEnd()) {
    if(reader.isStartElement()){
      if(reader.name()=="bookindex"){ // (c)
        readBookindexElement();
      }else{
        reader.raiseError(QObject::tr("Not a bookindex file"));
      }
    }else{
      reader.readNext();
    }
  }
  file.close();
  if(reader.hasError()){ // (d)
    std::cerr<<"Error: Failed to parse file"
      <<qPrintable(fileName)<<": "
      <<qPrintable(reader.errorString())<<std::endl;
    return false;
  }else if(file.error()!=QFile::NoError){
    std::cerr<<"Error: Cannot read file "<<qPrintable(fileName)
    	<<": "<<qPrintable(file.errorString())<<std::endl;
    return false;
  }
  return true;
}

其中:

  • (a):readFile()函数首先会尝试打开文件。如果失败,则会输出一条出错信息并返回false值;如果成功,则它将被设置为QXmlStreamReader的输人设备。
  • (b):QXmlStreamReader的readNext()函数从输人流中读取下一个记号。如果成功而且还没有到达XML文件的结尾,函数将进人循环。由于索引文件的结构,我们知道在该循环内部只有三种可能性发生:<bookindex>开始标签正好被读入;另一个开始标签正好被读入(在这种情况下,读取的文件不是一个书刊索引);读入的是其他种类的记号。
  • (c):如果有正确的开始标签,就调用readBookindexElement()继续完成处理。否则,就调用QXmlStreamReader::raiseError()并给出出错信息。下一次(在while循环条件下)调用atEnd()时,它将返还true值。这就确保了解析过程可以在遇到错误时能尽快停止。通过对QFile调用error()和errorString(),就可以在稍后查询这些出错信息。当在书刊索引文件中检测到有错误时,也会立即返回一个类似的出错信息。其实,使用raiseError()通常会更加方便,因为它对低级的XML解析错误和与应用程序相关的错误使用了相同的错误报告机制,而这些低级的XML解析错误会在QXmlStreamReader运行到无效的XML时就自动出现。
  • (d):一旦处理完成,就会关闭文件,如果存在解析器错误或者文件错误,该函数就输出一个出错信息并返回false值;否则,返回true值并报告解析成功。
void XmlStreamReader::readBookindexElement()
{
  reader.readNext();
  while(!reader.atEnd()){
    if(reader.isEndElement()){
      reader.readNext();
      break;
    }
    if(reader.isStartElement()){
      if(reader.name()=="entry"){
        readEntryElement(treeWidget->invisibleRootItem());
      }else{
        skipUnknownElement();
      }
    }else{
      reader.readNext();
    }
  }
}

readBookindexElement()的作用就是读取文件的主体部分。它首先跳过当前的记号(此处只可能是<bookindex>开始标签),然后遍历读取整个输人文件。

如果读取到了关闭标签,那么它只可能是</bookindex>标签,否则QXmlStreamReader早就已经报告出错。如果是那样的话,就跳过这个标签并跳出循环。否则将应该有一个顶级索引<entry>开始标签。如果情况确实如此,调用readEntryElement()来处理条目数据;不然,就调用skipUnknownElement()。使用skipUnknownElement()而不调用raiseError(),意味着如果要在将来扩展书刊索引格式以包含新的标签的话这个阅读器将继续存效,因为它仅忽略了不能识别的标签。

readEntryElement()具有一个确认父对象条目的QTreeWidgetItem *参数。我们将QTreeWidget::invisibleRootItem()作为父对象项传递,以使新的项以其为根基。在readEntryElement()中,用一个不同的父对象项循环调用readEntryElement()

void XmlStreamReader::readEntryElement(QTreeWidgetItem *parent)
{
  QTreeWidgetItem *item=new QTreeWidgetItem(parent);
  item->setText(0,reader.attributes().value("term").toString());
  reader.readNext();
  while(!reader.atEnd()) {
    if (reader.isEndElement()) {
      reader.readNext();
      break;
    }
    if (reader.isStartElement()) {
      if (reader.name()=="entry") {
        readEntryElement(item);
      } else if (reader.name()=="page") {
        readPageElement(item);
      } else {
        skipUnknownElement();
      }
    } else {
      reader.readNext();
    }
  }
}

每当遇到一个<entry>开始标签时,就会调用readEntryElement()函数。我们希望为每一个索引条目创建一个树形的窗口部件项,因此创建一个新的QTreeWidgetltem,并将其第一列的文本值设置为条目的项属性文本。

一旦条目被添加到树中,就开始读取下一个记号。如果这是一个关闭标签,就跳过该标签并跳出循环。如果遇到的是开始标签,那么它可能是<entry>标签(表示一个子条目),<page>标签 (该条目项的页码数),或者是一个未知的标签。如果开始标签是一个子条,就递归调用readEntryElement()。如果该标签是<page>标签,就调用readPageElement()

void XmlStreamReader::readPageElement(QTreeWidgetItem *parent)
{
  QString page=reader.readElementText();
  if (reader.isEndElement())
  	reader.readNext();
  QString allPages=parent->text(1);
  if (! allPages.isEmpty())
  	allPages +=", ";
  allPages +=page;
  parent->setText(1, allPages);
}

只要读取的是<page>标签,就调用readPageElement()函数。被传递的正是符合页码文本所属条目的树项。我们从读取<page>和</page>标签之间的文本开始。成功读取完以后,readElementText()函数将让解析器停留在必须跳过的</page>标签上。

这些页被存储在树形窗口部件项的第二列。我们首先提取那里已有的文本。如果文本不为空值,就在其后添加一个逗号,为新页的文本做好淮备。然后,添加新的文本并相应地更新该列的文本。

void XmlStreamReader::skipUnknownElement()
{
  reader.readNext();
  while (!reader.atEnd()) {
    if (reader.isEndElement()) {
      reader.readNext();
      break;
    }
    if (reader.isStartElement()) {
      skipUnknownElement();
    } else {
      reader.readNext();
    }
  }
}

最后,当遇到未知的标签时,将继续读取,直到读取到也将跳过的未知元素的关闭标签为止。这意味着我们将跳过那些具有良好形式但却无法识別的元素,并从XML文件中读取尽可能多的可识別的数据。

——————————————————

对于本文实例完整代码有需要的朋友,可关注并在评论区留言!

整理 | 王启隆

透过「历史上的今天」,从过去看未来,从现在亦可以改变未来。

今天是 2022 年 1 月 26 日,在 1997 年的今天,《纽约时报》在一篇关于新旧金山公共图书馆的文章中记录了电子书和纸质书之间的争论。当时的批评者抱怨说,图书馆为计算机终端牺牲了太多的书本空间,为在线信息牺牲了太多的书籍;人们感叹传统卡片目录的终结,这标志着许多图书馆进入了信息时代。你如今还会看纸质书吗?回首过去,看看历史上的 1 月 26 日还发生了哪些改变了我们如今生活习惯的关键事件。

1931 年 1 月 26 日:日本首批计算机的制造者 Eiichi Goto 出生

图源:维基百科

后藤英一(Eiichi Goto)出生于 1931 年 1 月 26 日,他是日本计算机科学家,日本第一台通用计算机的制造者。后藤出生于东京涩谷,1953 年毕业于成庆高中后,就读于东京大学。在高桥英寿的指导下,他继续在东京攻读物理学研究生课程,并于 1962 年获得博士学位。1959 年,他成为东京大学的教员。1968 年,他成为 RIKEN 信息科学实验室的首席科学家,直到 1991 年。后藤于 2005 年 6 月 12 日因糖尿病并发症逝世,享年 74 岁。

1954 年,当他还是一名研究生时,后藤英一发明了 Parametron ,这是一种将铁氧体磁芯与电容器相结合的电路元件,可产生可控制时序的电振荡。这为当时用于构建计算设备的真空管技术提供了一种替代方案。他于 1958 年基于参数的逻辑完成了日本制造的第一批通用计算机之一 PC-1 的构建,不久之后,后藤在 1961 年访问麻省理工学院期间设计了第一个时间最优解决方案来解决细胞自动机设计问题。后藤因在 Parametron 和 PC-1 方面的工作获得了 1959 年朝日奖,他于 1988 年获得大河内纪念技术奖,并于 1989 年因其在电子束成形方面的工作而被日本政府授予紫绶带荣誉勋章。

资料来源:维基百科

1947 年 1 月 26 日:万维网的共同发明人 Robert Cailliau 出生

罗伯特·卡里奥(Robert Cailliau)出生于 1947 年 1 月 26 日,他是一位比利时信息工程师、计算机科学家。他与其 CERN 同事蒂姆·伯纳斯-李一起开发了万维网(WWW)。他设计了万维网的历史标志,于 1994 年在 CERN 组织了第一次国际万维网会议,并于 1995 年帮助将 Web 开发从 CERN 转移到了全球 Web 联盟。卡里奥还与 James Gillies 博士一起撰写了《万维网是如何诞生的》,这是关于万维网起源的第一本长篇著作。

图源:维基百科

卡里奥出生于比利时通厄伦,1958 年他随父母搬迁到安特卫普。中学毕业后,他进入大学,于 1969 年以电子工程及机械工程方向的土木工程师专业毕业于根特大学。随后,他又于 1971 年在密歇根大学获得了计算机、信息与控制工程的理学硕士学位。在比利时军队服役期间,他维护了一个 Fortran 程序来模拟部队调动。

1974 年 12 月,他开始作为研究员在欧洲核子研究组织(CERN)的同步加速器(PS)部门工作,从事加速器控制系统的研究工作。1987 年 4 月,他离开 PS 部,成为数据处理部(Data Handling division)计算机系统办公室(Office Computing Systems)的团体领袖。1989 年,蒂姆·伯纳斯-李提出一个超文本系统,目的是为访问 CERN 文档及其相关的文档提供多种方式。伯纳斯-李在 1990 年 9 月至 12 月创建了系统,称其为万维网。这段时间内,卡里奥与伯纳斯-李联合发起了项目经费的计划。随后,卡里奥成为项目的关键支持者。

1993 年 12 月,他着手准备第一次国际万维网会议,会议最终在 1994 年 5 月举行。会议最终吸引了众多网络先驱来参加,达到 380 人,在网络的发展史上是一个里程碑。会议促使国际万维网会议委员会成立,从那时起每年都组织会议。1994 年,他与欧盟委员会启动了“Web for Schools”项目,将网络引入教育资源。在他协助将网络发展的任务从 CERN 转移到 W3C 后,他的时间都投入到公共通信的相关工作中。他于 2007 年 1 月提前从 CERN 退休。

如今提到万维网,很多人会想到蒂姆·伯纳斯-李,从而忽略卡里奥的名字,就好像提到苹果时很多人会想到乔布斯而忘了沃兹。但在万维网的历史和将来,卡里奥都是一个无比重要的组成部分;他经常在国际会议上发表许多主题演讲,如今他计划为全欧洲的互联网做贡献,致力于打造一个信息化的社会。你还知道哪些容易被忽视的互联网名人吗?欢迎在评论区分享。

资料来源:维基百科、百度百科

1983 年 1 月 26 日:曾经的电子表格软件霸主 Lotus 1-2-3 首次发布

Lotus 1-2-3,是美国莲花软件公司(Lotus Software)于 1983 年起所推出的电子表格软件,在 DOS 时期广为个人电脑用户所使用,是一套杀手级应用软件。但在 Windows 兴起后,微软铺天盖地营销其 Microsoft Office 软件,因此 Lotus 1-2-3 逐渐式微,退出了历史舞台。1980 年代后期,Lotus 1-2-3 因微软推出“Excel”而受到极大威胁,1988 年微软从莲花手上夺下 12%的市场,还在不断扩大战果。Lotus 1-2-3 因为是用汇编语言撰写的,在移植上有一定的难度,迟至二年后才推出。微软在操作系统平台的优势下,Excel 逐渐取代了 Lotus 1-2-3 ,成为主流的电子表格软件。

图源:CSDN 下载自东方 IC

美国莲花软件公司,是由米奇·卡普尔(Mitch Kapor)在 1982 年创建的软件公司,他们推出的 Lotus 1-2-3 红极一时,击败了微软的 Multiplan,几乎垄断了电子表格。Lotus 1-2-3 的命名原因是它本身所拥有的三大功能:第一、强大的表格(spreadsheet)功能;第二、图形集成功能;第三、简易数据库功能,故称为 1-2-3,在当时这三种功能原本是由三个不同的软件分别来执行。事实上其本身还具有文字处理、文件管理的功能。

1983 年 1 月 26 日,Lotus 1-2-3 首次发行,成为 IBM 兼容电脑的第一套杀手级应用软件,功能多而且运算速度快,很快就成为世界上第一个销售超过 100 万套的软件,当时微软的查尔斯·西蒙尼(Charles Simonyi)回忆说:“我第一次看到 Lotus 1-2-3,我就知道我们遇到麻烦了(I knew we were in trouble the first time I saw it.)”。第二版的 Lotus 1-2-3,被称为 Symphony,也有人叫它 Lotus 1-2-3-4-5,因为它在 1-2-3 的基础上又拼装了文字处理和通信功能。

在落败于 Excel 后,1995 年 6 月 11 日,IBM 于以 35 亿美元收购了莲花公司。莲花从此成为了 IBM 的一家子公司,而 Lotus 1-2-3 也成为了 IBM 公司的五大软件产品线(Information Management、Lotus、Rational、Tivoli、WebSphere)之一。如今,IBM Lotus 1-2-3 已于 2013 年 6 月 11 日停止销售,软件支持服务持续到了 2014 年 9 月 30 日正式结束。和微软争锋的软件很多,但能像网景和火狐一样存活下来,凤凰涅槃,并非一件易事。

资料来源:维基百科、百度百科

2000 年 1 月 26 日:XHTML 问世

XHTML,即“可扩展超文本标记语言”(Xtensible HyperText Markup Language),是一种标记语言,表现方式与超文本标记语言(HTML)类似,不过语法上更加严格。从继承关系上讲,HTML 是一种基于标准通用标记语言(SGML)的应用,是一种非常灵活的指标语言,而 XHTML 则基于可扩展标记语言(XML),XML 是 SGML 的一个子集。XHTML 1.0 在 2000 年 1 月 26 日成为 W3C 的推荐标准。

图源:CSDN 下载自东方 IC

XHTML 是 3 种 HTML 4 文件根据 XML 1.0 标准重组而成的;于 2002 年 8 月发表的 XHTML 1.0 的建议中,W3C 指出 XHTML 家族将会是 Internet 的新阶段。而转换使用 XHTML 可以令开发人员接触 XML 和其好处,并可以确保以 XHTML 开发的网页于未来的兼容性。HTML 语法要求比较松散,这样对网页编写者来说,比较方便,但对于机器来说,语言的语法越松散,处理起来就越困难,对于传统的电脑来说,还有能力兼容松散语法,但对于许多其他设备,比如手机,难度就比较大。因此产生了由 DTD 定义规则,语法要求更加严格的 XHTML。

大部分常见的浏览器都可以正确地解析 XHTML,即使老一点的浏览器,XHTML 作为 HTML 的一个子集,许多也可以解析。也就是说,几乎所有的网页浏览器在正确解析 HTML 的同时,可兼容 XHTML。当然,从 HTML 完全转移到 XHTML,还需要一些过程。总而言之,XHTML5 并非可扩展 HTML 的后继语言,而是对 XML 序列化的 HTML5 的称呼,延续了一部分原本 XHTML 的精神而加入 HTML5,成为 HTML5 规格的一部分。XHTML 1.1 就是 XHTML 最后的独立标准,2.0 止于草案阶段。XHTML5 则是属于 HTML5 标准的一部分,且名称已改为“以 XML 序列化的 HTML5”,而非“可扩展的 HTML”。如今,XHTML5 比起 HTML5 并非主流,W3C 也建议大多数人使用 HTML 语法,而不是 XHTML 语法。

资料来源:维基百科、百度百科

2011 年 1 月 26 日:知乎上线

知乎是一家创立于 2011 年 1 月 26 日的中国社会化问答网站,产品形态与美国在线问答网站 Quora 类似。“知乎”在文言文中意为“知道吗”,2012 年 2 月底,知乎使用“发现更大的世界”作为其宣传口号。截至 2017 年 9 月 20 日,知乎注册用户数超 1 亿 ,日活跃用户量达 2600 万,人均日访问时长 1 小时,月浏览量 180 亿。截至 2016 年 5 月,知乎累计产生了 1000 万个提问、3400 万个回答和 3500 万个赞同。2021 年至纽交所上市,不过仍未盈利。

知乎由北京智者天下科技有限公司所持有,其法律代表人是李大海。智者天下亦开发了包括 Android、iOS 平台的手机“知乎客户端”、“知乎群组”、“知乎日报”与“公益壹点通”四款手机应用程序。如今,在挖掘优质创作会员与投入自有内容的同时,随着多样性的社群文化增加,知乎越来越类似于 Reddit 等同好论坛,成为了许多人的互联网社交网站。

图源:CSDN 下载自东方 IC

知乎团队成员在创立初期只有十多人,周源和其同事李申申是知乎的联合创始人,分别担任知乎的 CEO 和 CTO;原创新工场的投资经理黄继新担任知乎的 COO;原网易微博产品经理黄海均担任知乎的产品经理;成远和胡维则负责知乎的产品运营。随着知乎的发展,知乎用户被称为知友,知乎团队人数也逐渐增多。知乎在创建初期邀请了大量互联网界的知名人士,如愿创建起了良好的基础氛围。在运营的过程中,知乎也通过“赞同、反对、没有帮助”等本身的投票功能,以及外部输出的知乎阅读、知乎日报等方式鼓励用户共享高质量的内容。

知乎中出现大量有一定特征的提问标题,如“如何评价/看待 XXX”、“XXX 是怎样的体验/怎样一番体验”等。此外,回答中的“谢邀”(感谢其他网友邀请回答问题)、“以上”(用于结尾表示回答完毕)等也是知乎体的特征之一。知乎的注册用户可以面向社群提出问题,也可以向指定的用户提出问题。每个用户在首页都可以看到自己所关注用户所回答、关注、赞同的问题,也可以看到所关注话题的更新。用户还可以邀请至多六名用户来回答某个问题。为了让用户及时获取自己感兴趣的内容,知乎员工会收集一些用户感兴趣的高质量回答,通过“每周精选”或“知乎阅读”的方式推送给用户。同时其领域功能能让用户系统地发现所感兴趣领域的优质问答。

随着互联网的发展,越来越多的人可以通过网络了解到以前不知道的知识;而问答网站作为以“人与人”交互的平台,让许多普通人也有了和专家在网络上面对面的机会,很多时候可以提供搜索引擎无法找到的偏僻知识。你认为在不久的未来里,人工智能和大数据会让搜索引擎发展到比人类回答专业知识还快吗?欢迎参与本期投票,在评论区分享你的真知灼见。

资料来源:维基百科、百度百科

2014 年 1 月 26 日:Google 收购 DeepMind

DeepMind 是一家英国的人工智能公司。公司由 Demis Hassabis、Shane Legg 和 Mustafa Suleyman 于 2010 年创立,最初名称是 DeepMind 科技(DeepMind Technologies Limited),在 2014 年被谷歌收购。DeepMind 公司总部位于伦敦,在加拿大、法国和美国。2015 年,DeepMind 成为谷歌母公司 Alphabet 的全资子公司。

图源:CSDN 下载自东方 IC

DeepMind 于 2014 年开始开发人工智能围棋软件 AlphaGo,2016 年,DeepMind 的 AlphaGo 程序在五场比赛中击败了人类职业围棋选手、世界冠军李世石。2017 年 10 月 19 日,AlphaGo 的团队在《自然》杂志上发表了一篇文章,介绍了 AlphaGo Zero,这是一个没有用到人类数据的版本,比以前任何击败人类的版本都要强大。通过跟自己对战,AlphaGo Zero 经过 3 天的学习,以 100:0 的成绩超越了 AlphaGo Lee 的实力,21 天后达到了 AlphaGo Master 的水平,并在 40 天内超过了所有之前的版本。2019 年 1 月 25 日,DeepMind 人工智能 AlphaStar 在《星际争霸 II》以 10:1 战胜人类职业玩家,改变了许多人对于“人工智能无法完成团队协作游戏”的印象。

2016 年,DeepMind 将其人工智能转向蛋白质折叠,这是科学中最棘手的问题之一。2018 年 12 月,DeepMind 的 AlphaFold 通过成功预测 43 种蛋白质中的 25 种最准确的结构,赢得了第 13 次蛋白质结构预测技术关键评估(CASP)。“这是一个灯塔项目,我们第一次在人力和资源方面对一个基本的、非常重要的、现实世界的科学问题进行重大投资,”哈萨比斯对卫报说。2020 年,在第 14 届 CASP 中,AlphaFold 的预测达到了与实验室技术相当的准确度分数。科学评审小组之一安德烈·克里什塔福维奇博士将这一成就描述为“真正了不起的”,并表示预测蛋白质如何折叠的问题已“基本解决”。

继 AlphaGo 之后,Google DeepMind 首席执行官 Demis Hassabis 曾表示将研究用人工智能与人类玩其他游戏,例如即时战略游戏《星际争霸 II》(StarCraft II)深度 AI 如果能直接使用在其他各种不同领域,除了未来能玩不同的游戏外,例如自动驾驶、投资顾问、音乐评论、甚至司法判决等等目前需要人脑才能处理的工作,基本上也可以直接使用相同的神经网络去学而习得与人类相同的思考力。你对于人工智能的极限都有哪些遐想呢?欢迎在评论区分享你的真知灼见。

【欢迎投稿】以史为镜,可以知兴替。计算机科学发展至今,有许多至关重要的事件、人物,欢迎所有朋友一起共建「历史上的今天」,投稿邮箱:tangxy@csdn.net 。

新程序员003》正式上市,50余位技术专家共同创作,云原生和数字化的开发者们的一本技术精选图书。内容既有发展趋势及方法论结构,华为、阿里、字节跳动、网易、快手、微软、亚马逊、英特尔、西门子、施耐德等30多家知名公司云原生和数字化一手实战经验!

件项目实训及课程设计指导——如何应用XML+XSLT技术分离Web表示层数据和样式

1、"XML+XSLT"技术在J2EE技术平台中的应用

Java语言及相关的应用技术的产生解决了跨平台的软件应用系统的开发,但没有解决如何实现跨平台的数据交换问题。在传统的软件应用系统中,为了能够实现在不同的系统平台之间交换数据、同时还要保证数据的完整性,是相对比较麻烦的一件事情。

基于此应用的目的和要求,诞生了XML(eXtensible Markup Language,可扩展标记语言)技术。应用XML语言可以实现软件应用系统中的"内容"与"表现"相互分离,并且XML还是一种可扩展的标签语言。

如下示例图中的代码为一个定义学生信息的XML格式文档示例,读者从此示例中可以了解到XML格式文档只定义数据内容(或者应用系统处理的最终结果),而这些数据或者结果最终在什么终端设备显示、以及以什么风格显示都没有定义。

基于XML语言及应用技术的XSLT(Extensible Stylesheet Language Transformations,扩展样式表转换语言)的主要作用是将XML由一种格式转换为另一种格式(当然,也可以为其它格式,如HTML网页,纯文字等),而在J2EE Web应用系统的开发实现中,应用XSLT技术能够实现将XML格式的源文档通过转换引擎并按照XSL(eXtensible Stylesheet Lanaguage,扩展样式表语言)模板的格式最终转换输出目标HTML格式的文档。

如下示例图中的代码为某个XSLT文档文件的内容,其中包含有<xsl:stylesheet>、<xsl:template>等标签,同时在<xsl:template></xsl:template>标签内包含有一个完整的HTML文件所应该具有的标签。这些标签都起什么作用?源XML文档最终在浏览器中的显示结果如何?

由于XSLT文档文件本身也是一个 XML格式的文档,因此它也总是由如下的XML声明语句起始:<?xml version="1.0" encoding="gb2312"?>

但由于本文章的篇幅有限,读者如果需要详细了解和学习XML、XSLT和XHTML等相关的语法、技术和应用等,可以参考作者的《J2EE Web核心技术——XHTML与XML应用开发》一书中相关章节内容。

读者也许还会有许多的疑问,比如为什么要多此一举?请读者保持耐心,继续往下阅读。

2、XSL技术概述及在J2EE系统平台中的应用

(1)XSL是什么

XSL就是可扩展样式表语言(eXtensible Stylesheet Lanaguage),XSL是参考SGML(Standard Generalized Markup Language,标准通用标记语言)中的DSSSL(Document Style Semanticsand Specification Language,文档样式语义和规范语言,它主要是用来设置SGML的表现样式)而设计的。

(2)为什么要提供XSL技术

尽管"CSS+Div"能够为Web应用系统的页面开发人员分离Web页面中的结构和风格,从而实现分离Web页面中的数据和表现。但如果其中的数据是采用XML格式表示,此时如果再继续采用CSS层叠样式表技术来为该XML格式文档数据设置表现样式,由于CSS层叠样式表采用的是与XML完全不同的一套语法规则定义,无法使用相同的XML解析器进行处理和解析,这为软件应用系统项目开发带来了许多额外的负担。

最初设计XSL的主要目的就是希望采用XML格式的语法规则提供一种为XML文档设置表现样式的新方法。而CSS的主要问题是由于没有逻辑控制的能力——CSS不能重新排序文档中的元素、也不能判断和控制哪个元素被显示、哪个不被显示、当然也不能统计计算元素中的数据等功能要求。

因此CSS层叠样式表技术一般只适合用于输出固定内容的最终Web页面文档,但CSS层叠样式表技术的主要优点是简洁、消耗系统资源少;而XSLT虽然功能强大,但因为要重新索引XML结构树,所以消耗系统内存量比较多。

在企业级的软件应用系统开发中,一般常常将CSS和XSLT两者相互结合使用。比如在Web服务器端用XSLT处理相关的文档,而在客户端则用CSS层叠样式表技术来控制数据在浏览器端的最终显示风格,这样的设计方案能够大大地减少响应时间。

3、XSL技术主要包括两个组成部分

XSL技术主要包括两个组成部分:XSLT(eXtensible Stylesheet Language Transformation)和XSL-FO(XSL Formatting Object)。

其中的XSLT主要是实现转换XML格式的文档,而XSL-FO主要是格式化XML文档。其中XSL-FO的作用就类似CSS层叠样式表技术在HTML页面中的作用,但作者在本文中重点为读者介绍XSLT相关的技术及应用。

因此,XSL从本质上可以看着为是一种可以将XML转化成其它类型语言的语言、一种可以过滤和选择XML数据的语言、一种能够格式化XML数据的语言。

4、XSLT主要是面向转换类型的应用

XSLT的主要作用是将XML文档数据内容由一种格式转换为另一种格式——比如,将XML格式的文档转换为HTML/XHTML(或者WML)等格式的文档是目前XSLT应用最为广泛的应用领域。

为什么要应用XSLT及相关的技术?因为XML格式的数据文档能够便于交换但不便于人类的阅读和理解、特别是机器自动化地阅读。因此如何能够按照人类的要求显示XML格式文档中的数据?如何实现将同一个XML格式文档中的数据在不同的显示平台中显示输出?

5、XSLT数据格式转换的基本实现原理

数据格式转换的重要思想是要把XML格式文档视为一种树形结构,转换的过程其实就是从源XML格式文档树生成结果树的过程。其中的XSL样式单定义了源XML格式文档树和结果树中对应部分的转换规则,在每条规则中包含了一个模板,并对应着一种模式——模板定义了转换的结果和转换的基本规则,而模式则规定了需要进行转换的元素或属性对象。

6、XSLT数据格式转换的实现过程

首先,将XML格式文档转换为DOM(Document Object Model,文档对象模型)树结构,这主要是利用XSLT来实现——XSLT处理器首先要做的是通过XML解析器(比如DOM或SAX)技术读取XML格式文档中的各个标签和数据,并将XML树状结构重新整理和组合产生出一个临时的树状结构,这个树状结构称为XML文档结果树。

其次,再对转换后的DOM树进行格式化并转换为其它的目标形式,这主要是利用XSL-FO来实现。XSL处理程序将这些数据转换(也就是格式化过程)为另一种格式良好的XML文件(如:WML、HTML、VoiceXML等)。

目前在微软IE浏览器中已经内嵌有实现这个转换过程的XML处理器程序。欢迎读者继续阅读作者的另一篇文章《软件项目实训及课程设计指导--应用XML+XSLT技术分离Web表示层数据和样式示例》可以详细学习和了解如何在软件应用系统开发中应用XML+XSLT技术。

7、应用XSLT实现对XML格式文档中的数据转换和合并的应用示例

为了能够让读者对"XML+XSLT"技术在企业级软件应用系统开发中的应用有感性的认识,作者在下文中给出一个典型示例加以说明。

在下面示例中的XML格式文档中的"学生信息"节点中有多个"班级"节点,可以通过XSLT中的<xsl:for-each>标签把这些节点数据在一个表格单元格中显示出来,从而产生出合并数据的应用效果。当然,也可以实现其它的应用效果,读者可以自行实现。

(1)示例中所对应的XML格式文档

该XML文档文件名称为student.xml,其中在<?xml-stylesheet?>标签中通过href属性指定对应的XSLT文件,该文件名称为student.xsl。

<?xml version="1.0" encoding="GB2312" standalone="yes" ?>
<?xml-stylesheet type="text/xsl" href="student.xsl" ?>
<软件学院学生信息>
      <学生信息 性别="男">
            <姓名>张三</姓名>
            <出生日期>1987/10/18</出生日期>
            <专业>软件工程</专业>
            <班级 方向="J2EE软件开发">软件1班</班级>
            <班级>9教东201</班级>
      </学生信息>
      <学生信息 性别="女">
            <姓名>李四</姓名>
            <出生日期>1988/2/18</出生日期>
            <专业>软件工程</专业>
            <班级 方向="数字媒体方向">软件2班</班级>
            <班级>9教东202</班级>
      </学生信息>
</软件学院学生信息>

(2)示例中的XML文档所对应的XSLT文档(student.xsl) 文件

在student.xsl 文件中应用了XSL语言中的一些标签,而XSLT文件中的标签语法大致可分为如下的三种类型:

1)选择模式,如<xsl:for-each>、<xsl:value-of>和 <xsl:apply-templates>等标签,这些选择模式的标签语句将数据从XML文档中提取出来,是一种简单获得数据的方法。在这些标签中都有一个select属性,选取XML文档中特定的节点名的数据。

2)测试(识别)模式,如<xsl:if> 和<xsl:when>等标签,类似于编程语言中的条件语句,主要是用于条件判断和识别等用途。

3)匹配模式,如<xsl:template>标签,它用于构建和定义一个模板。该标签中的match 属性主要是用于关联 XML文档中的标签元素和转换模板,但match 属性的值是 XPath (XML Path Language,XML路径语言)表达式(比如match="/" 则是定义整个XML格式文档);位于<xsl:template> 标签元素内部的内容则定义了写到输出结果的 HTML标签代码。

<?xml version="1.0" encoding="gb2312" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
    <xsl:template match="/">
          <html>
          <head>
          <title>XX交通大学软件学院学生信息</title>
          </head>
          <body>
          <xsl:apply-templates/>
          </body>
          </html>
    </xsl:template>
    <xsl:template match="软件学院学生信息">
          <h3>下面为XX交通大学软件学院学生信息表</h3>
          <table border="1">
          <th>姓名</th>
          <th>性别</th>
          <th>出生日期</th>
          <th>专业</th>
          <th>班级</th>
          <th>专业方向</th>
          <xsl:apply-templates/>
          </table>
    </xsl:template>
    <xsl:template match="学生信息">
          <tr>
          <td><xsl:value-of select="姓名"/></td>
          <td><xsl:value-of select="@性别"/></td>
          <td><xsl:value-of select="出生日期"/></td>
          <td><xsl:value-of select="专业"/></td>
          <td>
          <xsl:for-each select="班级">
          <xsl:value-of />
          </xsl:for-each>
          </td>
          <xsl:apply-templates/>
          </tr>
    </xsl:template>
    <xsl:template match="班级">
          <td><xsl:value-of select="@方向"/></td>
    </xsl:template>
</xsl:stylesheet>

在student.xsl 文件中应用了<xsl:apply-templates> 标签元素产生模板嵌套的应用效果,因为<xsl:apply-templates> 标签元素可把一个模板应用于当前的标签元素或者当前标签元素的子节点中。

如果向 <xsl:apply-templates> 标签元素添加一个 select 属性,则此标签元素就会仅仅处理与由其select 属性所定义的XML标签中属性值相匹配的XML标签元素,从而可以过滤XML标签。

(3)本示例在Web浏览器中最终执行的结果

如何应用CSS+Div分离Web表示层数据处理逻辑和展现逻辑

如何应用策略设计模式分离JDBC数据库连接中的外部环境信息

如何应用策略设计模式的思想设计通用的数据库连接类

如何正确地创建和销毁软件应用系统中JDBC数据库连接对象实例

如何应用观察者设计模式重构系统中日志处理功能实现的程序代码