忘记密码   免费注册 查看新帖 | 论坛精华区

ChinaUnix.net

  平台 论坛 博客 认证专区 大话IT HPC论坛 徽章 文库 沙龙 自测 下载 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 1336 | 回复: 8

XML::LibXML —— XML解析器的另一个选择(译) [复制链接]

论坛徽章:
0
发表于 2017-06-07 22:12 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-03 14:51 编辑

因为想了解perl如何处理xml及DOM,找到这篇文章,google翻译后,修改了一下。因为对某些方面缺乏实际经验可能有错。原文链接
http://www.xml.com/pub/a/2001/11/14/xml-libxml.html


XML::LibXML - An XML::Parser Alternative
XML::LibXML —— XML解析器的另一个选择

November 14, 2001

Kip Hampton


Introduction
介绍

The vast majority of Perl's XML modules are built on top of XML::Parser, Larry Wall and Clark Cooper's Perl interface to James Clark's expat parser. The expat-XML::Parser combination is not the only full-featured XML parser available in the Perl World. This month we'll look at XML::LibXML, Matt Sergeant and Christian Glahn's Perl interface to Daniel Velliard's libxml2.

绝大多数Perl的XML模块都建立在XML :: Parser之上,包括从Larry Wall和Clark Cooper的Perl接口,到James Clark的expat解析器。 expat-XML :: Parser组件不是Perl世界中唯一可用的全功能XML解析器。这一期,我们将看看Matt Sergeant和Christian Glahn实现的Perl接口XML :: LibXML,以及Daniel Velliard的libxml2。

Why Would You Want Yet Another XML Parser?
为什么需要另一个XML解析器?

Expat and XML::Parser have proven themselves to be quite capable, but they are not without limitations. Expat was among the first XML parsers available and, as a result, its interfaces reflect the expectations of users at the time it was written. Expat and XML::Parser do not implement the Document Object Model, SAX, or XPath language interfaces (things that most modern XML users take for granted) because either the given interface did not exist or was still being heavily evaluated and not considered "standard" at the time it was written.
Expat和XML :: Parser已经被证明是相当有能力的,但并不是没有局限。 Expat是最早可用的XML解析器之一,因此,其接口反映了那个时期使用者的期望。 Expat和XML :: Parser没有实现文档对象模型DOM,SAX或XPath语言接口(这些是大多数当代XML用户认为理所应当存在的),或者是因为给定的接口当时不存在,或者因为当时接口还有待严格测试,而不被视为“标准”。

The somewhat unfortunate result of this is that most of the available Perl XML modules are built upon one of XML::Parser's non- or not-quite-standard interfaces with the presumption that the input will be some sort of textual representation of an XML document (file, filehandle, string, socket stream) that must be parsed before proceeding. While this works for many simple cases, most advanced XML applications need to do more than one thing with a given document and that means that for each stage in the process, the document must be serialized to a string and then re-parsed by the next module.
这造成有点不幸的结果: 大多数可用的Perl XML模块都是基于XML :: Parser的“非标准接口”或“不是十分标准接口”构建的,假定输入的是XML文档的某种文本表示(文件,文件句柄,字符串,套接字流),对这些文本进行处理之前必须先解析。
虽然对于许多简单的情况不存在问题,但大多数高级XML应用场合,需要对特定文档执行多次操作,这意味着处理中的每个阶段,文档必须序列化为字符串,然后被下一个模块再次解析。

By contrast libxml2 was written after the DOM, XPath, and SAX interfaces became common, and so it implements all three. In-memory trees can be built by parsing documents stored in files, strings, and so on, or generated from a series of SAX events. Those trees can then be operated on using the W3C DOM and XPath interfaces or used to generate SAX events that are handed off to external event handlers. This added flexibility, which reflects current XML processing expectations, makes XML::LibXML a strong contender for XML::Parser's throne.
相比之下,libxml2是在DOM,XPath和SAX接口变得普遍之后编写的,因此它实现了所有三种接口。内存中的树,可以通过解析文档形式的文件来构建,也可以从字符串构建,或者从一系列SAX事件生成。然后可以使用W3C DOM和XPath接口来操作这些树,或者用于生成SAX事件,再将这些事件交付给外部处理程序。这增加了灵活性,反映了当前的XML处理期望,使XML :: LibXML成为XML :: Parser一统天下的强大竞争者。

Using XML::LibXML
使用XML :: LibXML

This month's column may be seen as a addendum to the Perl/XML Quickstart Guide published earlier this year, when XML::LibXML was in its infancy, and we'll use the same tests from the Quickstart to put XML::LibXML though its paces.
For a detailed overview of the test cases see the first installment in the Quickstart; but, to summarize, the two tests illustrate how to extract and print data from an XML document, and how to build and print, programmatically, an XML document from data stored in a Perl HASH using the facilities offered by a given XML module.
本月的专栏可以视为今年早些时候发布的“Perl / XML快速入门指南”的增编,当时XML :: LibXML处于起步阶段,我们将使用与Quickstart相同的测试,使XML :: LibXML经历相同的步骤。
有关测试用例的详细概述,请参阅Quickstart中的第一部分; 但是总而言之,这两个测试说明了如何从XML文档中提取和打印数据,以及如何使用给定的XML模块提供的功能,从存储在Perl HASH中的数据,以程序化的方式构建和打印出一个XML文档。

Reading
读xml文件

For accessing the data stored in XML documents, XML::LibXML provides a standard W3C DOM interface. Documents are treated as a tree of nodes and the data those nodes contain are accessed by calling methods on the node objects themselves.
为了访问存储在XML文档中的数据,XML :: LibXML提供了一个标准的W3C DOM接口。 文档被处理为一个节点树,这些节点包含的数据,可以通过调用节点对象本身的方法进行访问。

use strict;

use XML::LibXML;

my $file = 'files/camelids.xml';

my $parser = XML::LibXML->new();

my $tree = $parser->parse_file($file);

my $root = $tree->getDocumentElement;

my @species = $root->getElementsByTagName('species');

foreach my $camelid (@species) {

    my $latin_name = $camelid->getAttribute('name');

    my @name_node  = $camelid->getElementsByTagName('common-name');

    my $common_name = $name_node[0]->getFirstChild->getData;

    my @c_node  = $camelid->getElementsByTagName('conservation');

    my $status =  $c_node[0]->getAttribute('status');

    print "$common_name ($latin_name) $status \n";

}

One of the more exciting features of XML::LibXML is that, in addition to the DOM interface, it allows you to select nodes using the XPath language. The following illustrates how to achieve the same effect as the previous example using XPath to select the desired nodes:
XML :: LibXML更令人激动的功能之一是,除了DOM接口之外,它还允许您使用XPath语言选择节点。 以下说明如何使用XPath选择所需节点,达到与上一个例子相同的效果:

use strict;

use XML::LibXML;

my $file = 'files/camelids.xml';

my $parser = XML::LibXML->new();

my $tree = $parser->parse_file($file);

my $root = $tree->getDocumentElement;


foreach my $camelid ($root->findnodes('species')) {

    my $latin_name = $camelid->findvalue('@name');

    my $common_name = $camelid->findvalue('common-name');

    my $status =  $camelid->findvalue('conservation/@status');

    print "$common_name ($latin_name) $status \n";

}


What makes this exciting is that you can you can mix and match methods from the DOM and XPath interfaces to best suit the needs of your application, while operating on the same tree of nodes.
令人兴奋的是,您可以混合和搭配使用DOM和XPath接口中的方法,操纵同一棵树上的节点,以最佳地满足应用程序的需求。

Writing
写xml文件

To create an XML document programmatically with XML::LibXML you simply use the provided DOM interface:
要使用XML :: LibXML以编程方式创建XML文档,只需使用提供的DOM接口:

use strict;

use XML::LibXML;

my $doc = XML::LibXML::Document->new();

my $root = $doc->createElement('html');

$doc->setDocumentElement($root);

my $body = $doc->createElement('body');

$root->appendChild($body);

foreach my $item (keys (%camelid_links)) {

   my $link = $doc->createElement('a');

   $link->setAttribute('href', $camelid_links{$item}->{url});

   my $text = XML::LibXML::Text->new($camelid_links{$item}->{description});

   $link->appendChild($text);

   $body->appendChild($link);

}

print $doc->toString;



An important difference between XML::LibXML and XML::DOM is that libxml2's object model conforms to the W3C DOM Level 2 interface, which is better able to cope with documents containing XML Namespaces. So, where XML::DOM is limited to:
XML :: LibXML和XML :: DOM之间的一个重要区别是,libxml2的对象模型符合W3C DOM 标准2接口,它能够更好地处理包含XML命名空间的文档。 所以,XML :: DOM限于:

@nodeset = getElementsByTagName($element_name);
and
$node = $doc->createElement($element_name);



XML::LibXML also provides:
XML :: LibXML还提供:

@nodeset = getElementsByTagNameNS($namespace_uri, $element_name);
and
$node = $doc->createElementNS($namespace_uri, $element_name);


The Joy of SAX
SAX的可喜之处



Also in Perl and XML  
Perl和XML其它方面

OSCON 2002 Perl and XML Review
XSH, An XML Editing Shell
PDF Presentations Using AxPoint
Multi-Interface Web Services Made Easy
Perl and XML on the Command Line


We've seen the DOM and XPath goodness that XML::LibXML provides, but the story does not end there. The libxml2 library also offers a SAX interface that can be used to create DOM trees from SAX events or generate SAX events from DOM trees.
我们已经看到XML :: LibXML提供的DOM和XPath的好处,但故事并没有结束。 libxml2库还提供了一个SAX接口,可用于从SAX事件创建DOM树,或从DOM树生成SAX事件。

The following creates a DOM tree programmatically from a SAX driver built on XML::SAX::Base. In this example, the initial SAX events are generated from a custom driver implemented in the CamelDriver class that calls the handler events in the XML::LibXML::SAX::Builder class to build the DOM tree.
下面例子,是基于XML :: SAX :: Base,以编程方式,从SAX驱动程序,创建一个DOM树。 在这个例子中,最初的SAX事件,是从在CamelDriver类中实现的客户驱动程序生成的,它调用XML :: LibXML :: SAX :: Builder类中的事件处理程序来构建DOM树。

use XML::LibXML;

use XML::LibXML::SAX::Builder;

my $builder = XML::LibXML::SAX::Builder->new();

my $driver = CamelDriver->new(Handler => $builder);

my $doc = $driver->parse(%camelid_links);


# doc is an XML::LibXML::Document object

print $doc->toString;


package  CamelDriver;

use  base  qw(XML::SAX::Base);

sub parse {

  my $self = shift;

  my %links = @_;

  $self->SUPER::start_document;

  $self->SUPER::start_element({Name => 'html'});

  $self->SUPER::start_element({Name => 'body'});



  foreach my $item (keys (%camelid_links)) {

    $self->SUPER::start_element({Name => 'a',

                                   Attributes => {

                                     'href' => $links{$item}->{url}

                                               }

                                });

    $self->SUPER::characters({Data => $links{$item}->{description}});

    $self->SUPER::end_element({Name => 'a'});

  }



  $self->SUPER::end_element({Name => 'body'});

  $self->SUPER::end_element({Name => 'html'});

  $self->SUPER::end_document;

}

1;



You can also generate SAX events from an existing DOM tree using XML::LibXML::SAX::Generator. In the following snippet, the DOM tree created by parsing the file camelids.xml is handed to XML::LibXML::SAX::Generator's generate() method which in turn calls the event handlers in XML::Handler::XMLWriter to print the document to STDOUT.
您还可以使用XML :: LibXML :: SAX :: Generator,从现有的DOM树生成SAX事件。 在以下代码段中,通过解析文件camelids.xml创建的DOM树,该树被交给XML :: LibXML :: SAX :: Generator的generate()方法,该方法又调用XML :: Handler :: XMLWriter中的事件处理程序来打印 文件到STDOUT。
use strict;

use XML::LibXML;

use XML::LibXML::SAX::Generator;

use XML::Handler::XMLWriter;



my $file = 'files/camelids.xml';

my $parser = XML::LibXML->new();

my $doc = $parser->parse_file($file);

my $handler = XML::Handler::XMLWriter->new();

my $driver = XML::LibXML::SAX::Generator->new(Handler => $handler);



# generate SAX events that are captured

# by a SAX Handler or Filter.

$driver->generate($doc);



Resources   
资 源

Download the sample code.
Perl XML Quickstart: The Standard XML Interfaces
Writing SAX Drivers for Non-XML Data
Transforming Data With SAX Filters



This ability to accept and emit SAX events is especially useful in light of the recent discussion in this column of  generating SAX events from non-XML data and writing SAX filter chains.
You could, for example, use a SAX driver written in Perl to emit events based on data returned from a database query that creates a DOM object, which is then transformed in C-space for display using XSLT and the mind-numbingly fast libxslt library (which expects libxml2 DOM objects), and then emit SAX events from that transformed DOM tree for further processing using custom SAX filters to provide the finishing touches -- all without once having had to serialize the document to a string for re-parsing. Wow.
联系到上文讨论的“从非XML数据生成SAX事件,到写SAX过滤器”这一系列过程,接受和发出SAX事件的能力就特别有用。
例如,您可以使用Perl编写的SAX驱动程序,根据数据库查询返回的数据,创建DOM对象,从DOM对象发出事件,然后将其转换到C空间,以使用XSLT和快得令人惊叹的libxslt库 (它需要使用libxml2 DOM对象)来展示数据,然后从该转换的DOM树中发出SAX事件,以便使用客户定义SAX过滤器进行进一步处理,以提供最终结果,而无需一次将文档序列化为字符串进行重新解析。 哇!

Conclusions
结论

As we have seen, XML::LibXML offers a fast, updated approach to XML processing that may be superior to the first-generation XML::Parser for many cases. Do not misunderstand, XML::Parser and its dependents are still quite useful, well-supported, and are not likely to go away any time soon. But it is not the only game in town, and given the added flexibility that XML::LibXML provides, I would strongly encourage you to give XML::LibXML a closer look before beginning your next Perl/XML project.
如我们所见,XML :: LibXML提供了一种快速的新的XML处理方法,在许多情况下可能优于第一代XML :: Parser。 不要误会,XML :: Parser及其派生模块依然非常有用,得到很好的支持,不会很快消失。 但它并不是唯一的游戏,鉴于XML :: LibXML提供了更多的灵活性,我强烈建议您在开始下一个Perl / XML项目之前,尽可能地认真的研究一下XML :: LibXML。

论坛徽章:
0
发表于 2017-06-15 21:43 |显示全部楼层
我觉得这个贴发的不错呀!平时工作中看到不少人不知道用XML::LibXML,有些人还在用XML::Simple,有些人觉得XML::LibXML难上手。

实际上XML::LibXML在(Meta)CPAN上的文档有些分散,如果知道其关系的话还是很好上手的。比如DOM处理的话常用的有XML::LibXML::Node, XML::LibXML:ocument, XML::LibXML::Element(其中后两个继承了XML::LibXML::Node)这几个里面的方法。

另外Google上搜XML::LibXML tutorial有一个排在很前面叫Perl XML::LibXML by example,写的蛮好的,短小精悍而常见的东西都有cover。

论坛徽章:
0
发表于 2017-07-01 21:39 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-03 00:32 编辑

使用 LibXML2 处理配置文件(转)

https://www.ibm.com/developerworks/cn/aix/library/au-libxml2.html

学习如何在您的 UNIX® 应用程序中使用 XML(可扩展标记语言)。本文面向那些不熟悉 XML 的 UNIX 开发人员,研究了 Gnome 项目中开发的 XML 库。在从总体上对 XML 进行简单的解释之后,您将看到 UNIX 应用程序开发人员可能用来解析和管理 XML 格式的配置文件的示例代码,其中使用了 LibXML2 库。

引言

要创建完善的、高度互操作性的应用程序,XML 是一个很好的选择,因为它正越来越广泛地应用于数据存储和配置文件管理。本文研究了一个使用 XML(可扩展标记语言)作为其配置文件格式的示例应用程序,并通过该示例向您介绍如何在自己的 UNIX 应用程序中使用 XML。该示例应用程序使用 Perl 编写,并且其中使用了基于 Gnome 项目的 LibXML2 库的 Perl 模块。

在给出 XML 的简单定义之后,本文介绍了一个使用 XML 编写的示例配置文件。然后,通过示例代码来介绍如何解析这个配置文件。系统管理员可以手动修改该配置文件,但通常在一定程度上,需要应用程序直接地修改该配置文件。然后,本文通过一个示例介绍如何以编程的方式向这个 XML 文档添加新的配置选项,以及如何修改当前条目的值。最后,本文介绍了将这个经过修改的配置文件写入到磁盘的代码。

关于 XML

在开始研究 LibXML2 库之前,让我们先来巩固一下 XML 的相关基础。XML 是一种基于文本的格式,它可用来创建能够通过各种语言和平台访问的结构化数据。它包括一系列类似 HTML 的标记,并以树型结构来对这些标记进行排列。

例如,可参见清单 1 中介绍的简单文档。这是配置文件部分中研究的配置文件示例的简化版本。为了更清楚地显示 XML 的一般概念,所以对其进行了简化。

清单 1. 一个简单的 XML 文件

<?xml version="1.0" encoding="UTF-8"?>
<files>
  <owner>root</owner>
  <action>delete</action>
  <age units="days">10</age>
</files>

清单 1 中的第一行是 XML 声明,它告诉负责处理 XML 的应用程序,即解析器,将要处理的 XML 的版本。大部分的文件使用版本 1.0 编写,但也有少量的版本 1.1 的文件。它还定义了所使用的编码。大部分文件使用 UTF-8,但是,XML 设计用来集成各种语言中的数据,包括那些不使用英语字母的语言。

接下来出现的是元素。一个元素以开始标记 开始(如 <files>),并以结束标记 结束(如 </files>),其中使用斜线 (/) 来区别于开始标记。

元素是 Node 的一种类型。XML 文档对象模型 (DOM) 定义了几种不同的 Nodes 类型,包括 Elements(如 files 或者 age)、Attributes(如 units)和 Text(如 root 或者 10)。元素可以具有子节点。例如,age 元素有一个子元素,即文本节点 10。而 files 元素有七个子元素。其中三个很明显。它们分别是三个子元素:owner、action 和 age。其他四个分别是元素前后的空白文本符号。

XML 解析器可以利用这种父子结构来遍历文档,甚至修改文档的结构或内容。LibXML2 是这样的解析器中的其中一种,并且文中的示例应用程序正是使用这种结构来实现该目的。对于各种不同的环境,有许多不同的解析器和库。LibXML2 是用于 UNIX 环境的解析器和库中最好的一种,并且经过扩展,它提供了对几种脚本语言的支持,如 Perl 和 Python。

作为研究工作的第一步,让我们先来看一个示例配置文件。


配置文件

文中的示例应用程序读取了特定文件的操作列表。而配置文件定义了这些文件和操作。假设该配置文件是位于 UNIX 文件系统中某个位置的一个文件。例如,在 UNIX 系统 cron 中可能会使用这个配置文件。该 XML 文件定义了目录路径和根据条件要执行的操作,而这些条件则包括所有者和文件存在时间(请参见清单 2)。

清单 2. 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<filesystem>
   <path>
     <dirname>/var</dirname>
     <files>
       <owner>root</owner>
       <action>delete</action>
       <age units="days">10</age>
     </files>
     <files>
       <owner>any</owner>
       <action>delete</action>
       <age units="hours">96</age>
     </files>
   </path>
   <path>
     <dirname>/tmp</dirname>
     <files>
       <owner>any</owner>
       <action>delete</action>
       <age units="hours">24</age>
     </files>
   </path>
</filesystem>

在本例中,根 元素是 filesystem,它包含两个 path 元素。每个 path 元素包含相应的目录名和一个或多个 files 元素。每个 files 元素通过 age 元素的 units 属性中指定的存在时间单位,定义了当用户或用户文件达到特定的存在时间时,应用程序应采取的操作。请记住,空白符号是有意义的。从结构的观点来看,每个空白符号组成了独立的 Text 节点。

在产品环境中,一个编写完善的 UNIX 应用程序不仅应该具有读取数据并对其进行操作的能力,而且还应具有根据用户输入对数据进行添加、删除和修改的能力。

现在让我们来研究使用该数据的应用程序。


示例程序

本文余下的内容通过示例代码介绍对 XML 配置文件的解析和管理。这些示例逐一地读取并修改配置文件,但在 UNIX 开发人员的日常工作中,您可以在任何类型的任务中使用这些概念。而且,因为使用了 LibXML2 库,所以您可以将这些概念插入到几乎任何的 UNIX 应用程序中。

我们将在本文中介绍使用 Perl 版本的 LibXML2 库的示例。Internet 上的大部分文档都在讨论如何使用 Java? 或 Microsoft? Visual Studio 工具进行编程,但对于 UNIX 用户或开发人员来说,Perl 则更有价值。清单 3 显示了解析该 XML 文档所需的 Perl 模块。

清单 3. 需要的库

XML::LibXML
XML::LibXML::Common
XML::NamespaceSupport
XML::SAX

下面部分中介绍的代码仅仅只是一个框架。可分三个部分对其进行介绍:解析、操作和导出。

在加载和解析阶段中,可能会将数据加载到 Perl 变量中,如列表或哈希,但由于每个程序员都有他/她自己首选的方法来完成这项任务,所以我们把它留给读者作为一项练习。下面的代码只是简单地显示了数据,以此说明该脚本正确地找到了相应的数据。

在操作阶段中,该程序对 XML 文档中的元素进行添加、修改和删除的数据更新操作。通常地,这将按照用户的操作来进行。

最后在导出阶段中,将经过修改的最终的文档写回到磁盘。


加载和解析数据

对于应用程序来说,读取 XML 文件的第一步是加载该数据并将其解析为一个 Document 对象。在此基础上,可以对 DOM 树进行遍历以获取特定的节点。让我们来看看清单 4 中的代码是如何完成该任务的。

清单 4. 加载和解析 example.xml 的代码

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file("example.xml");
$filesystem = $doc->getDocumentElement();
@nodes=$filesystem->childNodes;
foreach $node (@nodes) {
  if($node->nodeType==ELEMENT_NODE) { # ignore text nodes
    # just get the first match
    @dirnames = $node->getElementsByTagName("dirname")->item(0);
    foreach $dirname (@dirnames) {
      print "dirname: " . $dirname->textContent . "\n";
      # push this into an array
    }
    # get all children
    @files = $node->getChildrenByTagName("files");
    foreach $file (@files) {
      foreach $values ($file->childNodes) {
        # ignore text nodes
        if($values->nodeType!=XML_TEXT_NODE) {
          if($values->nodeName() eq "age") {
            # check for attribute, otherwise, use default of 'hours'
            if($values->hasAttributes()) {
              print $values->nodeName() . ": " .  $values->textContent;
              print " " . $values->attributes->item(0)->value();
              print "\n";
            } else {
              print $values->nodeName() . ": " .  $values->textContent;
              print " hours\n";
            }
            # calculate extended value from units and put in a
            # hash linked with this dirname, etc.
          } else {
            print $values->nodeName() . ": " .  $values->textContent;
            print "\n";
            # put this value into a hash linked with $dirname.
            # We may have multiple entries for each $dirname, so
            # perhaps use an array within a hash
          }
        }
      }
    }
  }
}

首先,在清单 4 中,创建了解析器并将 XML 从文件加载到 XML::LibXML::Document 变量。这个对象包含了整个 XML 树,并且具有与之关联的各种方法可用来搜索节点、导出、验证和创建新的节点。本文将在后面的几个部分中对其中的一些方法进行介绍。从代码的起始处开始,您可以看到 getDocumentElement() 方法,它用于返回文档的根节点。从这个根节点,就可以遍历整个 XML 树。

主 foreach 循环对父 filesystem 元素中的每个节点进行循环。当仅选择元素节点时,该循环将得到 path 元素。getElementsByTagName() 方法根据相应的名称在节点中搜索对应的元素,并通过 NodeList 对象返回它们。每个 path 元素包含了一个 dirname 元素,所以代码搜索名称为 dirname 的元素,并获取其中的第一个条目。在代码中只能选择 ELEMENT 类型的节点,因为该方法不支持 TEXT 节点,并且会在 Perl 中产生一个不可恢复的错误。

在一个 path 元素中可能存在多个 files 元素,所以代码对 getChildrenByTagName() 方法的每一个元素进行循环,这个方法类似于 getElementsByTagName(),但仅搜索目标节点的直接子节点。这将返回所有的 files 元素,但必须进行进一步的解析以获得 owner、action 和 age 元素。在得到了这些节点之后,可以调用 textContent 以从相应的元素中获取实际的值。下面显示的是选择 ELEMENT 节点孩子的 TEXT 节点值的快捷方法:

print $values->nodeName() . ": "
print $values->firstChild()->nodeValue();

在使用 age 元素的情况下,还可以通过一个属性来指定时间单位。使用 hasAttributes() 和 Attributes 函数,该程序可以提取相应的属性,如果它存在话。如果它不存在,那么该程序使用缺省值 hours。

现在让我们来介绍对数据的操作,这样就能够以编程的方式来添加、删除和编辑操作。


对数据进行操作

现有的代码本身就是一个有用的程序。用户可以很容易地以手动地方式对该 XML 文件完成程序所做的修改。然而,有经验的 UNIX 开发人员还可以使用 XML 函数在程序中直接对文件进行修改。例如,可以包含用于添加新的操作或删除现有操作的菜单选项。要实现这个目的,让我们来看看在程序中对数据进行操作的代码。

清单 5. 向文档添加填充的 path 节点

$newnode = $doc->createElement("path");
$newdirnode = $doc->createElement("dirname");
$newdirnode->appendText("/root");
$newfilesnode = $doc->createElement("files");
$newownernode = $doc->createElement("owner");
$newownernode->appendText("any");
$newactionnode = $doc->createElement("action");
$newactionnode->appendText("archive");
$newagenode = $doc->createElement("age");
$newagenode->appendText("30");
$newagenode->setAttribute("units","days");
$newfilesnode->addChild($newownernode);
$newfilesnode->addChild($newactionnode);
$newfilesnode->addChild($newagenode);
$newnode->addChild($newdirnode);
$newnode->addChild($newfilesnode);
$filesystem->addChild($newnode);

清单 5 中的代码创建了一个 path 元素,并为其填充了所有的元素。然后,将这个新创建的节点添加到根元素,即 filesystem。需要使用 XML::LibXML::Document 类的 createElement() 方法来创建每个元素。(正是 Document 创建了您所需要的任何新的节点。)该方法返回一个尚未连接到文档树中任何位置的空节点。然后可以使用 XML::LibXML::Element  类的 appendText() 方法为每个节点添加内容。此外,相对于创建一个新的 TEXT 节点,然后对其进行填充并将其添加到相应的元素,这是一种快捷的方法。可以使用 setAttribute() 方法来添加属性,如果在目标元素中不存在给定名称的属性,该方法将自动创建一个新的 ATTRIBUTE 节点。

在完成每个节点的创建并分别对它们进行了填充之后,可以使用要求的子节点作为参数,对父节点调用 addChild() 方法。因此在上面的代码中,$newownernode 成为了 $newfilesnode 的子节点。文档中所有的节点保持其添加时的顺序。如果您希望指定其他的顺序,可以使用 insertAfter() 或 insertBefore() 函数。

将每个节点添加到相应的父节点,直到最后将主父节点添加到已经存在于文档中的一个节点。在上面的示例中,将该节点添加到了 filesystem 根节点。(如果您是从头开始创建该文档,那么可以对 Document 对象本身调用 addChild() 来添加根元素,然后再向该元素添加任何其他的节点。)

正如前面所解释的,清单 2 中的示例 XML 代码是一种可读的格式。换行和缩进使得文档更容易阅读。XML 解析器将读取所有这些字符,并将其作为一个 TEXT 类型的节点。清单 5 中的示例没有添加任何这样的 TEXT 节点。因此,该示例的输出将不包含任何换行或缩进。如果您希望创建这种空白字符,那么需要使用 XML::LibXML::Text 类来创建 TEXT 类型的节点,或者使用该文档对象的 createTextNode() 函数。该构造函数的返回值是一个节点,可以使用与上面示例中相同的方式将其添加到树中。

要更改文件的内容,可以直接设置相关 TEXT 节点的 nodeValue(),或者替换整个元素:

$newnode = $doc->createElement("owner");
$newnode->appendText("toor");
$oldnode->replaceNode($newnode);

要删除一个节点,有以下几种选择。一种方法是仅将其从结构中删除,代码如下所示:

$file->unbindNode();

在找到需要删除的节点之后,通过一行命令即可将其从结构中删除,但并没有从文档中删除。这个函数调用直到程序结束时才真正销毁该数据结构。如果您需要将节点移动到树中的其他部分,那么可以使用相同的变量来调用 addNode() 以将其重新添加到文档中新的位置。您还可以使用 removeChild() 或 removeChildNodes() 函数,这样可以从文档中彻底地释放相应的资源。



保存 XML 文件

在一些编程语言中,将 XML 文档保存到文件中可能比较烦琐,但幸运的是,LibXML 让这项任务变得非常简单:

$doc->toFile("example.xml");

在对数据进行的所有的操作中,这是最简单的一种操作。在对内存中的 XML 文档完成了相应的修改之后,只需使用一个函数调用就可以将其写回到对应的配置文件中。还可以使用相关的 Perl 函数,如 toString() 和 toFH(),这些函数分别将 XML 输出到一个字符串变量或者一个已打开的 Perl 文件句柄,而文件句柄将为您的应用程序的构建带来更大的灵活性。


结束语

通过提供 LibXML2 库以及对 Perl 模块的支持,Gnome 项目完成了一项很有价值的任务。本文对管理和使用 XML 配置文件所需要的三个重要的步骤进行了介绍。解析阶段可能是最复杂的,因为它需要一定程度的递归设计来解析 XML 树。尽管有些烦琐,但对内存中 XML 文档的操作却是非常简单明了的。使用 LibXML2 库导出经过修改的配置,也是非常容易的。

尽管相对于标准的UNIX 思维方式来说,需要进行一定的思维模式转移,但是 XML 可以为数据管理提供一种功能强大的方法。与简单的数据库格式相比,树型结构提供了更加灵活的数据视图。在开发新的应用程序或修改旧的应用程序时,可将其规范化为使用 XML 配置文件,在进行规范化的过程中可以很容易地使用 Gnome 项目所提供的免费的标准库,正如本文所介绍的。


论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
发表于 2017-07-02 17:02 |显示全部楼层
回复 1# hztj2005
大神,能不能将满屏的表情弄一弄。看着实在是有损您帖子的质量。

论坛徽章:
0
发表于 2017-07-03 15:10 |显示全部楼层
3楼的文字下面一段,我摸索了几个小时,解释一下:

清单 1. 一个简单的 XML 文件

<?xml version="1.0" encoding="UTF-8"?>
<files>
   <owner>root</owner>
   <action>delete</action>
   <age units="days">10</age>
</files>
元素是 Node 的一种类型。XML 文档对象模型 (DOM) 定义了几种不同的 Nodes 类型,包括 Elements(如 files 或者 age)、Attributes(如 units)和 Text(如 root 或者 10)。元素可以具有子节点。例如,age 元素有一个子元素,即文本节点 10。而 files 元素有七个子元素。其中三个很明显。它们分别是三个子元素:owner、action 和 age。其他四个分别是元素前后的空白文本符号。
----------------------------------------------------------
files 元素有七个子元素。其中三个很明显。它们分别是三个子元素:owner、action 和 age。其他四个分别是元素前后的空白文本符号。
我在编辑器中,删除所有的空格,存为example.xml,然后用下面代码验证子节点数目,发现一直是7,令人费解。后来发现“换行符”也属于“空白文本符号”,只有把example.xml中的换行符删掉,子节点数目才是3。

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file("example.xml");
$filesystem = $doc->getDocumentElement();
@nodes=$filesystem->childNodes;
my $nodesnum = @nodes;
print "\$nodesnum:".$nodesnum."\n";

论坛徽章:
0
发表于 2017-07-03 17:51 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-05 12:31 编辑

Perl and XML
http://www.xml.com/pub/at/15


The Perl programming language has a wealth of support for XML. Kip Hampton's column is the essential companion for Perl developers working with XML.
Perl语言对XML有着大量的支持。 Kip Hampton的专栏是Perl开发人员使用XML的重要伙伴。

OSCON 2002 Perl and XML Review
O'Reilly 开源会议 2002年会Perl-XML总结
By Kip Hampton
In this month's Perl and XML column, Kip Hampton reviews the state of the Perl-XML world as displayed at O'Reilly's Open Source Convention. [Aug. 21, 2002]
在本月的Perl和XML专栏中,Kip Hampton回顾了 “O'Reilly 开源会议” 所呈现的Perl-XML世界的状态。
OSCON2002指O'Reilly's Open Source Convention 2002,即“O'Reilly 开源会议 2002年会”。

XSH, An XML Editing Shell
XSH,一个XML编辑shell
By Kip Hampton
In this month's Perl and XML column, Kip Hampton introduces XSH, an XML editing shell, which Kip suggests should become a part of your XML tool kit. [Jul. 10, 2002]
在本月的Perl和XML专栏中,Kip Hampton介绍了XSH,一个XML编辑shell(指运行XSH后,在类似命令行的状态中处理XML),Kip建议,XSH应该成为XML工具包的一部分。
An Shell,按惯例指操作系统外围的人机交互的命令行界面,比如PERL中的安装模块cpan就有点象一个Shell,我们执行cpan后,就出现cpan>,提示我们输入其它命令。
PDF Presentations Using AxPoint
By Kip Hampton
In this month's Perl and XML column, Kip Hampton describes AxPoint, a way to create presentations in PDF using Perl and XML. [Jun. 19, 2002]
使用AxPoint制作XML的PDF格式演示文稿
在本月的Perl和XML专栏中,Kip Hampton描述了AxPoint,这是一种使用Perl和XML在PDF中创建演示文稿的方法。

Multi-Interface Web Services Made Easy
多种方法,Web服务可轻松实现

By Kip Hampton
This month's Perl and XML column offers a range of methods for easily building web applications with SOAP, REST, and XML-RPC interfaces. [May. 8, 2002]
本月的Perl和XML列提供了一系列方法,使用SOAP,REST和XML-RPC接口,轻松构建的Web应用程序。
Perl and XML on the Command Line
命令行上的Perl和XML
By Kip Hampton
In this month's Perl and XML column, Kip Hampton explores how the desperate Perl hacker can use its XML tools on the command line. [Apr. 17, 2002]
在本月的Perl和XML专栏中,Kip Hampton探讨了急切的Perl黑客如何在命令行中使用其XML工具。

Introducing XML::SAX::Machines, Part Two
介绍XML :: SAX :: Machines模块,第二部分
By Kip Hampton
This month, Kip Hampton's introduction to Perl's XML::SAX::Machines tool continues, adding flexibility to Apache-based apps and demonstrating the construction of a SAX controller. [Mar. 20, 2002]
本月,Kip Hampton继续介绍Perl的XML :: SAX :: Machines工具,为基于Apache的应用程序,增添了灵活性,并展示了SAX控制器的构建方法。

Introducing XML::SAX::Machines, Part One
介绍XML :: SAX :: Machines模块,第一部分
By Kip Hampton
XML::SAX::Machines offers an elegant way of building and managing complex chains of SAX event handlers and generators. Kip Hampton introduces this helpful module. [Feb. 13, 2002]
XML :: SAX :: Machines提供了的优雅方式,用于构建和管理复杂连串SAX事件的处理程序和生成程序。 Kip Hampton介绍了这个有用的模块。
Web Content Validation with XML::Schematron
使用XML :: Schematron进行Web内容验证
By Kip Hampton
Kip Hampton explains how to use his XML::Schematron module to validate XML Web content with Perl. [Jan. 23, 2002]
Kip Hampton解释了如何在Perl中,使用他的XML :: Schematron模块来验证XML Web内容。
XML and Modern CGI Applications
By Kip Hampton
Kip Hampton explores a modern CGI module, CGI::XMLApplication, which uses XML and XSLT to separate logic and presentation cleanly. [Dec. 12, 2001]

XML::LibXML - An XML::Parser Alternative
XML :: LibXML - XML :: Parser Alternative
By Kip Hampton
Kip Hampton discusses XML::LibXML, a capable, updated alternative to Perl's venerable and venerated XML::Parser. [Nov. 14, 2001]
Kip Hampton讨论了XML :: LibXML,这是Perl中一直被看重的XML :: Parser的一个有效的、更新的替代品。
Transforming XML With SAX Filters
使用SAX过滤器转换XML
By Kip Hampton
Kip Hampton concludes his series of advanced SAX topics by showing how to use SAX filters to transform XML. [Oct. 10, 2001]
Kip Hampton通过展示如何使用SAX筛选器转换XML,来结束他的一系列高级SAX主题。

Writing SAX Drivers for Non-XML Data
为非XML数据编写SAX驱动程序
By Kip Hampton
Kip Hampton shows us how to write drivers to produce SAX events and, thus, XML documents from non-XML data sources. [Sep. 19, 2001]
Kip Hampton向我们展示了如何编写驱动程序来生成SAX事件,从而为非XML数据源提供XML文档。

Creating VoiceXML Applications With Perl
使用Perl创建VoiceXML应用程序
By Kip Hampton
Kip Hampton shows you how to use VoiceXML and Perl to connect the telephone to the Web. [Aug. 9, 2001]
Kip Hampton向您展示,如何使用VoiceXML和Perl将电话连接到Web。

Creating Scalable Vector Graphics with Perl
用Perl创建可缩放矢量图形

By Kip Hampton
Kip Hampton demonstrates how to use Perl, XML, and SVG to generate useful and attractive graphics dynamically. [Jul. 11, 2001]
Kip Hampton演示了如何使用Perl,XML和SVG,动态生成有用和有吸引力的图形。

Perl XML Quickstart: Convenience Modules
Perl XML快速入门:便利模块
By Kip Hampton
The third and final part of our guide to Perl XML modules covers some handy modules geared to specific tasks. [Jun. 13, 2001]
Perl XML模块指南的第三部分和最后一部分,涵盖了一些适用于特定任务的方便的模块。[六月 13,2001]

Perl XML Quickstart: The Standard XML Interfaces
Perl XML快速入门:标准XML接口
By Kip Hampton
In the second part of our guide to XML and Perl, we cover the Perl implementations of the standard XML APIs DOM, SAX, and XPath. [May. 16, 2001]
在我们的XML和Perl指南的第二部分,我们介绍了标准XML 应用程序 DOM,SAX和XPath的Perl实现。

Perl XML Quickstart: The Perl XML Interfaces
Perl XML快速入门:Perl XML接口
By Kip Hampton
This first installment of our guide to Perl and XML covers Perl-specific interfaces for reading and writing XML. [Apr. 18, 2001]
Perl和XML指南的第一部分,包含了用于读取和写入XML的Perl特定接口。

Using XML::Twig
使用XML :: Twig
By Kip Hampton
XML::Twig provides a fast, memory-efficient way to handle large XML documents, which is useful when the needs of your application make using the SAX interface overly complex.  [Mar. 21, 2001]
XML :: Twig提供了一种快速,高效利用内存的处理大型XML文档的方式,当您的应用程序,使用SAX界面过于复杂时,这很有用。[三月 21,2001]

High-Performance XML Parsing With SAX
使用SAX高性能解析XML
By Kip Hampton
Manipulating XML documents in Perl using DOM or XPath can hit a performance barrier with large documents -- the answer is to use SAX. [Feb. 14, 2001]
使用DOM或XPath在Perl中处理XML文档,可能会遇到大型文档的性能障碍 – 解决方法是使用SAX。

Creating Web Utilities Using XML::XPath
使用XML :: XPath创建Web Utilities
By Kip Hampton
Using XML on your web site means more than just valid XHTML: our monthly Perl and XML column explores some possibilities for the automation of an all-XML web site. [Jan. 10, 2001]
在您的网站上使用XML意味着,不仅仅是判断XHTML是否合乎语法:本月Perl和XML专栏,探索了一个全XML网站自动化的一些可能性。


Using XML and Relational Databases with Perl
使用XML和关系数据库与Perl

By Kip Hampton
This article explores how Perl can be used to transfer data between XML and relational databases, and how XML can bridge two disparate databases. [Dec. 13, 2000]
本文探讨了Perl如何用于在XML和关系数据库之间传输数据,以及如何利用XML在两个不同种类的数据库中架起桥梁。

Simple XML Validation with Perl
Perl简单的XML验证
By Kip Hampton
A combination of Perl and XPath can provide a quick, lightweight solution for validating documents. Find out how in the first installment of our new monthly Perl and XML column. [Nov. 8, 2000]
Perl和XPath的组合,可以为验证XML文档,提供一个快速,轻便的解决方案。
具体方法请阅读我们最新的月度Perl和XML专栏的第一部分。

论坛徽章:
0
发表于 2017-07-03 17:52 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-03 17:54 编辑

重复发帖,删除

论坛徽章:
0
发表于 2017-07-04 22:00 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-04 22:16 编辑

Simple XML Validation with Perl(译)
使用Perl 轻易检测XML文档格式合法性
http://www.xml.com/pub/a/2000/11/08/perl

November 8, 2000

Kip Hampton

The Problem: Although XML Schemas and RELAX promise fine-grained validation for XML documents, neither are presently available in the Perl world. You need a way to validate the structure of your documents now. Today. Preferably before lunch.
问题:虽然XML Schemas和RELAX承诺对XML文档进行细致的验证,但两者在Perl世界目前均不存在。 您现在需要一种验证文档结构的方法,那么就是今天, 午餐之前。

The Solution: Combine the simplicity of Test.pm from the standard Perl distribution with the flexibility of XPath.
解决方案:将标准发布Perl版本中的Test.pm的简单性与XPath的灵活性相结合。

Overcoming Test Anxiety
克服测试焦虑

Before we show how Perl can make XML validation simple, we need to take a small detour through the standard Test module.
在我们展示Perl如何使XML验证变得简单之前,我们需要稍微绕一绕,说说标准测试模块Test 。
For those not familiar with it, the Test module was designed to give the harried hacker an easy way to ensure that his or her code passes a series of basic functional test before they unleash it on the world, and, in the case of writing modules, that those same tests are passed on the system on which the code is being installed.
对于不熟悉的人员,测试模块的设计目的是给忙碌的电脑高手一种简单的方式,以确保他或她的代码在世界各地发布之前,通过一系列基本功能测试;而在编写模块的情况下,这些相同的测试能在安装代码的系统上通过。
It is not surprising, then, that using Test.pm is a very straightforward proposition. Each test is defined as call to the function ok(), which takes up to three arguments: a test, an expected return value and an optional message to display upon failure. If the interpolated values of the first two arguments match, the test succeeds. An an example, consider the following two tests:

那么,就不奇怪,使用Test.pm是一个很通常的建议。 每个测试被设定为对ok()函数的调用,它最多可以有三个参数:一个测试,一个预期的返回值,和一个在失败时显示的可选消息。 如果前两个参数插入的值相匹配,则测试成功。 作为例子,考虑以下两个测试:

ok('good','good', 'its all good');

# this test passes because the first two arguments return the same values.
#此测试通过,因为前两个参数返回相同的值。

ok(sub { 2+2 }, 5, '2 and 2 is 4');

# this test fails for the obvious mathematical reason and prints a descriptive error.
由于明显的数学原因,此测试失败,并打印出描述性错误。

Following the XPath
跟着XPath

Now what does Test have to do with validating an XML document? The answer lies in its combination with the XML::XPath module. The XPath language provides a simple, powerful syntax for navigating the logical structure of an XML document. XML::XPath allows us to take advantage of that power from within Perl.
现在,测试Test与验证XML文档有什么关系?答案在于它与XML :: XPath模块的组合。 XPath语言为导航XML文档的逻辑结构,提供了一种简单而强大的语法。 XML :: XPath允许我们利用Perl拥有的这种能力。

XPath's syntax is quite accessible. For example, the XPath expression /foo/bar will find all of the "bar" elements contained within all "foo" elements that are children of the root node (the root element denoted by the leading "/"). Alternately, the expression /foo/bar/* will return the same nodes as the previous example, and bring all of the "bar" elements' descendants along for the ride.
XPath的语法是很容易存取。例如,XPath表达式/foo/bar,将在根节点(“/”表示根元素)的所有子节点“foo”元素中,找到包含于其中的所有“bar”元素。
或者,表达式/ foo / bar / *将返回与上一个示例相同的节点,顺带列出所有“bar”元素的下级子孙节点。


XPath also provides a number of functions and shortcuts that further simplify examining a document's structure. For instance, count(/foo/bar[@name]) will return the number of "bar" elements that have the attribute "name". As we will soon see, combining Test.pm's compact syntax with the simple power of XPath expressions will allow us to tackle the task of validating an XML document simply and efficiently.
XPath还提供了一些功能和快捷方式,可以进一步简化检查文档的结构。例如,count(/ foo / bar [@name])将返回具有“name”属性的“bar”元素的数量。正如我们马上看到的那样,将Test.pm的紧凑语法,与XPath表达式的简单有力相结合,将使我们能够简单有效地解决验证XML文档的任务。

Rolling Our Own XML Validator
运转我们自己的XML验证器

Let's try out what we've covered so far by creating our own simple XML validation tool. To do this, we will need a sample XML file, a test script, and simple Perl "wrapper" script to allow our tool to validate more than a single type of document. We begin with the Perl script, which we will call xml_test.pl. (You can also download the script.)
让我们创建自己简单的XML验证工具,试一试我们迄今为止所包括的内容。 为此,我们将需要一个示例性的XML文件,测试脚本和简单的Perl“包装器”脚本,以使我们的工具能够验证不止一种类型的文档。 我们从Perl脚本开始,我们将其称为xml_test.pl。 (您也可以下载脚本。)


use Test::Harness qw(&runtests $verbose);

use strict;

while(@ARGV > 2) {

    my $arg = shift @ARGV;

    if ($arg eq '-d') {

        $verbose = 1;

    }

}

if (@ARGV < 2) {

    usage();

    exit(0);

}

sub usage {

    warn "Usage: xml_test.pl [-d] testscript xmlfile\n";

}

$ENV{XMLFILE} = $ARGV[1];

runtests $ARGV[0];


This script allows us to be more flexible in our testing, by providing a way to specify both the XML file and the test file from the command line. Let's move on to creating a sample XML instance that we intend to validate. (Download the sample file here.)
通过提供从命令行指定XML文件和测试文件的方法,该脚本允许我们在测试中更灵活。 下一步,我们创建一个我们打算验证的示例XML实例。(在此下载示例文件。)

<?xml version="1.0" standalone="yes"?>

<order>

<customer>

  <name>Coyote, Ltd.</name>

  <shipping_info>

    <address>1313 Desert Road</address>

    <city>Nowheresville</city>

    <state>AZ</state>

    <zip>90210</zip>

  </shipping_info>

</customer>

<item>

  <product id="1111">Acme Rocket Jet Pack</product>

  <quantity type="each">1</quantity>

</item>

<item>

  <product id="2222">Roadrunner Chow</product>

  <quantity type="bag">10</quantity>

</item>

</order>

Now let's consider what tests would be appropriate to validate this type of document. At the very least, we need to verify that the document contains an order, and that the order contains a customer, a shipping address, and a list of items. Beyond that, we should also verify that each item contains a product and a quantity. So, we'll need five tests to verify the basic structure.
现在我们来考虑一下什么样的测试适合验证上面这类的文档。至少,我们需要验证该文档是否包含一个订单,并且该订单包含一个客户,一个送货地址和一个项目列表。 除此之外,我们还应该验证每个项目是否包含产品和数量。 所以,我们需要五个测试来验证基本结构。

Let's create a small test script named order.t (download order.t here). and begin with the basics.
我们来创建一个名为order.t的小测试脚本(这里下载order.t),从基础开始。

use Test;

BEGIN { plan tests => 5 }

use XML::XPath;

my $xp = XML::XPath->new(filename => 'customer_order.xml');

my (@nodes, $test); # pre-declare a few vars

First we'll define a test that checks whether or not the document root is indeed an "order" element. We will do this by attempting to select the nodeset for an "order" element at the document root into an array, testing that the resulting array contains only one element, and then verifying that our test is true.
首先我们定义一个测试,检查文档根部是否确实是一个“order”元素。 我们将通过尝试在文档根部中选取出(select)一个“order”元素的节点集(nodeset),然后测试生成的数组只包含一个元素,然后验证我们的测试是否为真。

@nodes = $xp->findnodes('/order');
OK(@nodes == 1, 1, "the root element must be an 'order'");

Next we need to confirm that our order document contains a "customer" element, and that the "customer" element contains a "shipping_info" element. Rather than running separate tests for each, we can combine these tests into a single expression and, if either element is missing or misplaced, our test will fail.
接下来,我们需要确认我们的订单文档包含一个“customer”元素,“customer”元素包含一个“shipping_info”元素。 我们可以将这些测试结合到单一表达式中,而不是分别运行测试,如果任一元素丢失或错位,我们的测试将失败。

@nodes = $xp->findnodes('/order/customer/shipping_info');

ok(@nodes == 1, 1, "an order must contain a 'customer'
                    element with a 'shipping_info' child");


As the Perl mantra goes, "There's More Than One Way To Do It", and the same is true with XML::XPath. Rather than selecting the nodes into an array and evaluating that array in a scalar context to get the number of matches, we can use the XPath count()  function to achieve the same effect. Note that we will be using XML::XPath's find() function instead of findnodes() since the type of test we are performing returns a literal value instead of a set of document nodes.
正如Perl的口头禅,“有不止一种方法来做某件事”,XML :: XPath也是如此。 我们可以使用XPath count()函数来实现相同的效果,而不是将节点提取到数组中,并在标量上下文中评估该数组以获得符合条件的数目。 请注意,我们将使用XML :: XPath的find()函数而不是前面用到的findnodes(),因此,我们执行的测试类型,返回一个文字值,而不是一组文档节点。

$test = $xp->find('count(/order/item)');

ok($test > 0, 1, "an order must contain at least one 'item' element");



Finally, we need to be sure that every "item" element contains both a "product" element and a "quantity" element. Here we'll get a little fancier and use XPath's boolean() function which returns true (1) only if the entire expression we pass to it evaluates to true. We need only check that the number of "item" elements is equal to the number of "item" elements that have the child elements we are testing for.
最后,我们需要确保每个“item”元素都包含“product”元素和“quantity”元素。 在这里,我们将得到一个小技巧,并使用XPath的boolean()函数,它返回true(1),只有当我们传递给它的整个表达式求值为true。 我们只需要检查“item”元素的数量,等于以我们测试的元素为子元素的“item”元素的数量。


$test = $xp->find( 'boolean(count(/order/item/product) = count(/order/item/))');

ok($test1 == 1, 1, "a 'item' element must contain a an 'product' element.");


$test = $xp->find( 'boolean(count(/order/item/quantity)=count(/order/item))');

ok($test1 == 1, 1, "a 'item' element must contain a 'quantity' element.");



We now have tests to cover the five basic areas that we defined earlier as the most critical in terms of structural validation. Having saved our test file as order.t, let's fire up our xml_test.pl script.
我们现在已经进行了测试,以覆盖我们之前定义的五个基本领域,作为结构验证最重要的准则。 将我们的测试文件保存为order.t后,让我们启动我们的xml_test.pl脚本。


% perl xml_test.pl -d order.t customer_order.xml

order.................1..5

OK 1

OK 2

OK 3

OK 4

OK 5

OK

All tests successful.
所有测试成功。

Files=1, Tests=5, 1 wallclock secs ( 0.69 cusr + 0.07 csys = 0.76 CPU)

Great, our sample document passed muster. But what if it didn't? To find out, open customer_order.xml, remove one of the "quantity" elements, save the file, and run the script again.

很好,我们的样本文件通过检测了。 但怎样才通不过呢? 要找出这种情况,打开customer_order.xml,删除一个“数量”元素,保存文件,然后再次运行该脚本。
order.................1..5

OK 1

OK 2

OK 3

OK 4

not OK 5

# Test 5 got: '' (order.t at line 26)

# Expected: '1' (a 'item' element must contain a 'quantity' element.)

FAILED test 5

Failed 1/5 tests, 80.00% okay

Failed Test Status Wstat   

Total Fail Failed List of failed

-------------------------------------------------------------

order.t 5 1 20.00% 5

Failed 1/1 test scripts, 0.00% okay. 1/5 subtests failed, 80.00% okay.



Admittedly the output is not very pretty, but it is functional. We now know that the current document is invalid, and we also know why.
诚然,输出不是非常漂亮,但它有效。 我们现在知道,指定的文件是不符合语法的,我们也知道为什么。

The handful of tests that we currently have clearly would not be sufficient validation for a production environment, but with these few examples, you hopefully have a clear view of the basics and could extend the test script to handle nearly any case. You could, for example, iterate over the "quantity" elements and test each text() node against a regular expression to ensure that each contained only a numeric value. You are limited only by your imagination.
我们目前显而易见的几项测试,对于生产环境来说,不是足够的验证,但是通过这几个例子,您有希望能够清楚地了解基础知识,并可以扩展测试脚本来处理几乎任何情况。 例如,您可以遍历“数量”元素,并用正则表达式测试每个text()节点,以确保每个元素仅包含一个数值。只要你想得到,你就做得到。

The Same Old Scheme?
同样的老方案?

Other Resources
其他资源

• Using XSL as a Validation Language by Rick Jelliffe
•使用XSL作为验证语言,by Rick Jelliffe

• Introducing the Schematron by Uche Ogbuji
•介绍Schematron,by Uche Ogbuji


As much as I would love to take credit for basic ideas presented here, I admit that the notion of using XPath expressions to validate an XML document's structure is not at all new. In fact, this concept is the foundation of Rick Jelliffe's popular Schematron. Thanks should also go to Matt Sergeant, the author of AxKit, for pointing out that Perl's Test and Test::Harness modules would make a nifty environment for a Perl Schematronesque clone. The goal here has been to spark your imagination, to get you to experiment, and, hopefully, to point to the ability of Perl and its modules to make even the more complex XML tasks, like validation, easy to solve.
尽管我足够信任这里提供的基本想法,但我承认,使用XPath表达式验证XML文档结构的概念,并不全然是新的方法。 事实上,这个概念是Rick Jelliffe很流行的Schematron的基础。 也要感谢AxKit的作者Matt Sergeant,他指出,Perl的Test和Test :: Harness模块将为Perl Schematronesque复制品,创造一个漂亮的环境。 这里的目标是激发您的想象力,让您进行实验,并希望指出Perl及其模块,能够使更复杂的XML任务(如验证),易于解决。


论坛徽章:
0
发表于 2017-07-05 10:27 |显示全部楼层
本帖最后由 hztj2005 于 2017-07-05 10:33 编辑

XML处理行政隶属关系

  1. use XML::XPath;
  2. use Test::Simple tests => 1;
  3. use Encode;
  4. use utf8;

  5. my $parser = XML::LibXML->new;
  6. my $dom_document = $parser->parse_file('xzqh.xml')
  7. or die "can't parse Rosie's stock file: $@";

  8. my $root = $dom_document->getDocumentElement;


  9. #下面语句用XML::XPath判断行政隶属关系,不能越级使用
  10. my @nodes = $root->findnodes('/中国/河北省/石家庄市/鹿泉市');

  11. ok(@nodes ==  1, "right!");

  12. #下面语句用XML::LibXML直接查询
  13. showsonnode("鹿泉市");

  14. sub showsonnode
  15. {
  16.           my $domain = shift;  #
  17.           my @countyList = $dom_document->getElementsByTagName($domain);

  18.                 foreach my $node(@countyList)
  19.                 {
  20.                         print $node->getName(),"===\n";
  21.                          print $node->textContent,"\n";#OK,输出子节点内容  代码页chcp 65001下,使用
  22.                         #print encode("gb2312",$node->getName()),"===\n";
  23.                          #print encode("gb2312",$node->textContent),"\n";#OK,输出子节点内容代码页 chcp936下使用
  24.                         
  25. #                        for my $child ($node->getChildNodes())
  26. #                        {
  27. #                                        if($child->nodeType == XML_TEXT_NODE)#忽略文字节点,实际是换行符节点
  28. #                                        {
  29. #                                                next;
  30. #                                        }        
  31. #                                
  32. #                                   print encode("gb2312","子节点名称:"),encode("gb2312",$child->getName());
  33. #                                   print "\n";
  34. #                                   if($child->hasAttributes())
  35. #                                   {         
  36. #                          print encode("gb2312","级别:");#getData()
  37. #                          print encode("gb2312",$child->attributes->item(0)->value())."\n";         
  38. #                       }
  39. #                                   print encode("gb2312",$child->textContent),"\n";#getData()
  40. #                                   
  41. #                        }
  42.                 }
  43. }
复制代码


下面是不完整的中国行政隶属xzqh.xml文件,保存为utf8格式
  1. <中国 ji="0">

  2. <北京市 ji="1">
  3. <brief>辖16市区、2县。共130个街道、36个地区、136个镇、18个乡[其中5个民族乡]。注:地区即乡或镇,是同一块地方、两块牌子,分别负责辖区内居民和农民的管理</brief>
  4. <东城区 ji="3"><brief>辖10个街道</brief>
  5. 安定门街道 建国门街道 朝阳门街道 东直门街道 东华门街道 和平里街道 北新桥街道 交道口街道 景山街道 东四街道
  6. </东城区>

  7. <西城区 ji="3"><brief>辖7个街道</brief>
  8. 月坛街道 德胜街道 新街口街道 西长安街街道 展览路街道 什刹海街道 金融街街道
  9. </西城区>
  10. <崇文区 ji="3"><brief>辖7个街道</brief>
  11. 天坛街道 东花市街道 前门街道 龙潭街道 永定门外街道 崇文门外街道 体育馆路街道
  12. </崇文区>
  13. <宣武区 ji="3"><brief>辖8个街道</brief>
  14. 大栅栏街道 天桥街道 椿树街道 陶然亭街道 广安门内街道 牛街街道 白纸坊街道 广安门外街道
  15. </宣武区>
  16. <朝阳区 ji="3"><brief>辖23个街道、20个地区(19个乡、1个民族乡)</brief>
  17. 朝外街道 劲松街道 亚运村街道 望京街道 团结湖街道 呼家楼街道 三里屯街道 香河园街道 双井街道 建外街道 和平街街道 垡头街道 酒仙桥街道 六里屯街道 麦子店街道 潘家园街道 小关街道 安贞街道 八里庄街道 左家庄街道 机场街道 大屯街道 东湖街道 南磨房地区(乡) 三间房地区(乡) 高碑店地区(乡) 豆各庄地区(乡) 太阳宫地区(乡) 奥运村地区(乡) 来广营地区(乡) 小红门地区(乡) 东风地区(乡) 王四营地区(乡) 管庄地区(乡) 将台地区(乡) 黑庄户地区(乡) 常营地区(回族乡) 平房地区(乡) 东坝地区(乡) 孙河地区(乡) 金盏地区(乡) 崔各庄地区(乡) 十八里店地区(乡)
  18. </朝阳区>

  19. <丰台区 ji="3"><brief>辖14个街道、2个地区、2个镇、3个乡</brief>
  20. 丰台街道 西罗园街道 方庄地区 太平桥街道 东铁匠营街道 右安门街道 长辛店街道 新村街道 卢沟桥街道 云岗街道 东高地街道 南苑街道 大红门街道 马家堡街道 和义街道 宛平地区 卢沟桥乡 花乡乡 南苑乡 长辛店镇 王佐镇
  21. </丰台区>
  22. <石景山区 ji="3"><brief>辖10个街道</brief>
  23. 老山街道 古城街道 金顶街街道 北辛安街道 鲁谷街道 八宝山街道 五里坨街道 广宁街道 苹果园街道 八角街道
  24. </石景山区>

  25. <清河街道 ji="3"><brief>辖22个街道、2个地区(乡)、5个镇</brief>
  26. 万柳地区(海淀乡) 东升地区(乡) 曙光街道 温泉镇 西北旺镇 苏家坨镇 万寿路街道 羊坊店街道 甘家口街道 八里庄街道 紫竹院街道 北下关街道 北太平庄街道 海淀街道 中关村街道 学院路街道 清河街道 青龙桥街道 香山街道 西三旗街道 马连洼街道 花园路街道 田村路街道 上地街道 清华园街道 燕园街道 永定路街道 上庄镇 四季青镇
  27. </清河街道>
  28. <门头沟区 ji="3"><brief>辖4个街道、9个镇</brief>
  29. 潭柘寺镇 永定镇 龙泉镇 军庄镇 妙峰山镇 王平镇 雁翅镇 斋堂镇 清水镇 大峪街道 城子街道 东辛房街道 大台街道
  30. </门头沟区>

  31. <房山区 ji="3"><brief>辖4个街道、1个地区、14个镇、6个乡</brief>
  32. 良乡镇 长阳镇 城关街道 周口店镇 琉璃河镇 十渡镇 大石窝镇 燕山地区 青龙湖镇 阎村镇 佛子庄乡 河北镇 张坊镇 窦店镇 蒲洼乡 新镇街道 韩村河镇 霞云岭乡 长沟镇 史家营乡 南窖乡 石楼镇 大安山乡 拱辰街道 西潞街道
  33. </房山区>
  34. <通州区 ji="3"><brief>辖4个街道、10个镇、1个民族乡</brief>
  35. 永顺镇 梨园镇 宋庄镇 张家湾镇 漷县镇  马驹桥镇 西集镇 潞城镇 台湖镇 永乐店镇 于家务回族乡 中仓街道 新华街道 北苑街道 玉桥街道
  36. </通州区>

  37. <顺义区 ji="3"><brief>辖6个街道、19个镇</brief>
  38. 空港街道 旺泉街道 双丰街道 胜利街道 光明街道 石园街道 仁和镇 马坡镇 南法信镇 天竺镇 后沙峪镇 杨镇 牛栏山镇 李桥镇 高丽营镇 赵全营镇 南彩镇 北小营镇 李遂镇 木林镇 龙湾屯镇 张镇 大孙各庄镇 北石槽镇 北务镇
  39. </顺义区>
  40. <昌平区 ji="3"><brief>辖2个街道、15个镇</brief>
  41. 城南街道 城北街道 北七家镇 百善镇 兴寿镇 崔村镇 南邵镇 流村镇 长陵镇 东小口镇 马池口镇 小汤山镇 阳坊镇 沙河镇 十三陵镇 回龙观镇 南口镇
  42. </昌平区>

  43. <大兴区 ji="3"><brief>辖3个街道、4个地区、14个镇</brief>
  44. 兴丰街道 林校路街道 清源街道 亦庄地区(亦庄镇) 黄村地区(黄村镇) 旧宫地区(旧宫镇) 西红门地区(西红门镇) 青云店镇 采育镇 安定镇 礼贤镇 榆垡镇 庞各庄镇 北臧村镇 魏善庄镇 长子营镇 瀛海镇
  45. </大兴区>
  46. <怀柔区 ji="3"><brief>辖2个街道、3个地区、9个镇、2个民族乡</brief>
  47. 泉河街道 龙山街道 怀柔地区 雁栖地区 庙城地区 北房镇 杨宋镇 桥梓镇 怀北镇 汤河口镇 渤海镇 九渡河镇 琉璃庙镇 宝山镇 长哨营满族乡 喇叭沟门满族乡
  48. </怀柔区>
  49. <平谷区 ji="3"><brief>辖2个街道、3个地区、11个镇、2个民族乡</brief>
  50. 滨河街道 兴谷街道 平谷镇 熊儿寨乡 马坊地区 夏各庄镇 马昌营镇 黄松峪乡 峪口地区 镇罗营镇 金海湖地区 刘家店镇 大华山镇 山东庄镇 大兴庄镇 王辛庄镇 东高村镇 南独乐河镇
  51. </平谷区>
  52. <延庆县 ji="3"><brief>辖11个镇、4个乡</brief>
  53. 延庆镇 康庄镇 八达岭镇 永宁镇 旧县镇 张山营镇 四海镇 千家店镇 沈家营镇 大榆树镇 井庄镇 大庄科乡 刘斌堡乡 香营乡 珍珠泉乡
  54. </延庆县>

  55. <密云县 ji="3"><brief>辖2个街道、17个镇、1个地区(民族乡)</brief>
  56. 鼓楼街道 果园街道 密云镇 河南寨镇 十里堡镇 西田各庄镇 溪翁庄镇 穆家峪镇 巨各庄镇 东邵渠镇 大城子镇 太师屯镇 北庄镇 新城子镇 古北口镇 高岭镇 不老屯镇 冯家峪镇 石城镇 檀营地区(满族蒙古族乡)
  57. </密云县>
  58. </北京市>
  59. <天津市 ji="1">
  60. <brief>辖16个区、2个县。共101个街道、100个镇、14个乡</brief>  
  61. <和平区 ji="3"><brief>辖6个街道</brief>  
  62. 劝业场街道 小白楼街道 体育馆街道 新兴街道 南营门街道 南市街道  
  63. </和平区>

  64. <河东区 ji="3"><brief>辖13个街道</brief>
  65. 大王庄街道 大直沽街道 中山门街道 富民路街道 二号桥街道 春华街道 唐家口街道 向阳楼街道 常州道街道 上杭路街道 东新街道 鲁山道街道 天津铁厂街道  
  66. </河东区>
  67. <河西区 ji="3"><brief>辖13个街道</brief>  
  68. 大营门街道 下瓦房街道 桃园街道 挂甲寺街道 马场街道 越秀路街道 友谊路街道 天塔街道 尖山街道 陈塘庄街道 柳林街道 东海街道 梅江街道  
  69. </河西区>

  70. <南开区 ji="3"><brief>辖12个街道</brief>
  71. 长虹街道 鼓楼街道 兴南街道 广开街道 万兴街道 学府街道 向阳路街道 嘉陵道街道 王顶堤街道 水上公园街道 体育中心街道 华苑街道
  72. </南开区>
  73. <河北区 ji="3"><brief>辖个10街道</brief>
  74. 光复道街道 望海楼街道 鸿顺里街道 新开河街道 铁东路街道 建昌道街道 宁园街道 王串场街道 江都路街道 月牙河街道  
  75. </河北区>

  76. <红桥区 ji="3"><brief>辖10个街道</brief>
  77. 西于庄街道 双环村街道 咸阳北路街道 丁字沽街道 西沽街道 三条石街道 邵公庄街道 芥园道街道 铃铛阁街道 大胡同街道  
  78. </红桥区>
  79. <塘沽区 ji="3"><brief>辖11个街道、1个镇</brief>  
  80. 新村街道 解放路街道 三槐路街道 新港街道 向阳街道 杭州道街道 新河街道 大沽街道 北塘街道 渤海石油街道 胡家园街道 新城镇  
  81. </塘沽区>

  82. <汉沽区 ji="3"><brief>辖5个街道、4个镇</brief>  
  83. 汉沽街道 寨上街道 河西街道 天化街道 盐场街道 大田镇 杨家泊镇 茶淀镇 营城镇  
  84. </汉沽区>
  85. <大港区 ji="3"><brief>辖5个街道、3个镇</brief>  
  86. 迎宾街道 胜利街道 古林街道 海滨街道 港西街道 太平镇 小王庄镇 中塘镇  
  87. </大港区>

  88. <东丽区 ji="3"><brief>辖5个街道、3个镇、1个乡</brief>  
  89. 张贵庄街道 丰年村街道 万新街道 无瑕街道 新立街道 军粮城镇 大毕庄镇 华明镇 么六桥乡
  90. </东丽区>
  91. <西青区 ji="3"><brief>辖2个街道、7个镇</brief>  
  92. 西营门街道 李七庄街道 中北镇 杨柳青镇 辛口镇 张家窝镇 南河镇 大寺镇 王稳庄镇  
  93. </西青区>

  94. <津南区 ji="3"><brief>辖8个镇</brief>  
  95. 咸水沽镇 葛沽镇 小站镇 双港镇 辛庄镇 双桥河镇 八里台镇 北闸口镇 长青办事处  
  96. </津南区>
  97. <北辰区 ji="3"><brief>辖3个街道、9个镇</brief>  
  98. 果园新村街道 集贤里街道 普东街道 天穆镇 北仓镇 双街镇 双口镇 青光镇 宜兴埠镇 小淀镇 大张庄镇 西堤头镇  
  99. </北辰区>

  100. <武清区 ji="3"><brief>辖6个街道、19个镇、5个乡</brief>  
  101. 杨村街道 下朱庄街道 东蒲洼街道 黄庄街道 徐官屯街道 运河西街道 梅厂镇 大碱厂镇 崔黄口镇 大良镇 下伍旗镇 南蔡村镇 大孟庄镇 泗村店镇 河西务镇 城关镇 东马圈镇 黄花店镇 石各庄镇 王庆坨镇 汊沽港镇 河北屯镇 上马台镇 大王古庄镇 陈咀镇 豆张庄乡 曹子里乡 大黄堡乡 高村乡 白古屯乡  
  102. </武清区>
  103. <宝坻区 ji="3"><brief>辖19个镇、3个乡</brief>  
  104. 城关镇 大口屯镇 大白庄镇 王卜庄镇 方家庄镇 林亭口镇 八门城镇 大钟庄镇 新安镇 马家店镇 霍各庄镇 新开口镇 大唐庄镇 高家庄镇 口东镇 牛道口镇 史各庄镇 郝各庄镇 周良庄镇 牛家牌乡 尔王庄乡 黄庄乡  
  105. </宝坻区>

  106. <宁河县 ji="3"><brief>辖11个镇、3个乡</brief>  
  107. 芦台镇 宁河镇 苗庄镇 丰台镇 岳龙镇 板桥镇 潘庄镇 造甲城镇 七里海镇 大北涧沽镇 东棘坨镇 北淮淀乡 俵口乡 廉庄子乡  
  108. </宁河县>
  109. <静海县 ji="3"><brief>辖16个镇、2个乡</brief>  
  110. 静海镇 唐官屯镇 独流镇 王口镇 台头镇 子牙镇 陈官屯镇 中旺镇 大邱庄镇 蔡公庄镇 梁头镇 团泊镇 双塘镇 大丰堆镇 沿庄镇 西翟庄镇 良王庄乡 杨成庄乡
  111. </静海县>

  112. <蓟县 ji="3"><brief>1个街道、20个镇、5个乡、1民族乡</brief>
  113. 文昌街道、渔阳镇、洇溜镇、官庄镇、马伸桥镇、下营镇、邦均镇、别山镇、尤古庄镇、上仓镇、下仓镇、罗庄子镇、白涧镇、五百户镇、侯家营镇、桑梓镇、东施古镇、下窝头镇、杨津庄镇、出头岭镇、西龙虎峪镇、穿芳峪乡、孙各庄满族乡、东二营乡、许家台乡、礼明庄乡、东赵各庄乡
  114. </蓟县>
  115. </天津市>
  116. <河北省 ji="1">
  117. <石家庄市 ji="2"><brief>辖6个市辖区、12个县,代管5个县级市。共51个街道、120个镇、102个乡[其中3个民族乡]</brief>     
  118. <长安区 ji="3"><brief>辖8个街道、3个镇</brief>   
  119. 建北街道  青园街道  广安街道  育才街道  跃进街道  河东街道  长丰街道  谈固街道  西兆通镇  南村镇  高营镇   
  120. </长安区>

  121. <桥东区 ji="3"><brief>辖9个街道、1个镇</brief>   
  122. 中山东路街道  彭后街道  东风街道  东华街道  休门街道  阜康街道  建安街道  胜北街道  汇通街道  桃园镇     
  123. </桥东区>
  124. <桥西区 ji="3"> (辖11个街道、1个乡)   
  125. 东里街道  中山路街道  南长街道  维明街道  裕西街道  友谊街道  红旗街道  新石街道  苑东街道  西里街道  振头街道  留营乡
  126. </桥西区>

  127. <新华区 ji="3"><brief>辖11个街道、2个镇、2个乡</brief>   
  128. 革新街道  新华路街道  宁安街道  东焦街道  西苑街道  合作路街道  联盟街道  石岗街道  五七街道  天苑街道  北苑街道  大郭镇  赵陵铺镇  西三庄乡  杜北乡   
  129. </新华区>
  130. <井陉矿区 ji="3"><brief>辖2个街道、2个镇、1个乡</brief>   
  131. 矿市街道  四微街道  贾庄镇  凤山镇  横涧乡     
  132. </井陉矿区>

  133. <裕华区 ji="3"><brief>辖8个街道、2个镇</brief>  
  134. 裕兴街道  裕强街道  东苑街道  建通街道  槐底街道  裕华路街道  裕东街道  长江街道  宋营镇  方村镇   
  135. </裕华区>
  136. <辛集市 ji="3"><brief>辖8个镇、7个乡</brief>   
  137. 辛集镇  旧城镇  张古庄镇  位伯镇  新垒头镇  新城镇  南智丘镇  王口镇  天宫营乡  前营乡  马庄乡  和睦井乡  田家庄乡  中里厢乡  小辛庄乡
  138. </辛集市>

  139. <藁城市 ji="3"><brief>辖13个镇、1个民族乡</brief>   
  140. 廉州镇  兴安镇  贾市庄镇  南董镇  梅花镇  岗上镇  丘头镇  南营镇  张家庄镇  南孟镇  增村镇  常安镇  西关镇  九门乡     
  141. 晋州市 (辖8个镇、2个乡)   
  142. 晋州镇  总十庄镇  营里镇  桃园镇  东卓宿镇  马于镇  小樵镇  槐树镇  东里庄乡  周家庄乡     
  143. </藁城市>
  144. <新乐市 ji="3"> (辖1个街道、8个镇、2个乡、1个民族乡)   
  145. 长寿街道  化皮镇  承安镇  正莫镇  南大岳镇  杜固镇  邯邰镇  东王镇  马头铺镇  协神乡  木村乡  彭家庄回族乡   
  146. </新乐市>

  147. <鹿泉市 ji="3"> (辖8个镇、4个乡)   
  148. 获鹿镇  寺家庄镇  李村镇  黄壁庄镇  铜冶镇  上庄镇  宜安镇  大河镇  石井乡  白鹿泉乡  上寨乡  山尹村乡     
  149. </鹿泉市>
  150. <井陉县 ji="3"> (辖10个镇、7个乡)   
  151. 微水镇  上安镇  天长镇  秀林镇  南峪镇  小作镇  威州镇  南障城镇  苍岩山镇  测鱼镇  吴家窑乡  北正乡  于家乡  孙庄乡  南陉乡  辛庄乡  南王庄乡     
  152. </井陉县>

  153. <正定县 ji="3"> (辖1个街道、4个镇、5个乡)   
  154. 南城区街道  正定镇  诸福屯镇  新城铺镇  新安镇  南牛乡  南楼乡  西平乐乡  北早现乡  曲阳桥乡     
  155. </正定县>
  156. <栾城县 ji="3"> (辖5个镇、3个乡)     
  157. 楼底镇  郄马镇  冶河镇  窦妪镇  栾城镇  南高乡  柳林屯乡  西营乡     
  158. </栾城县>

  159. <行唐县 ji="3"> (辖4个镇、11个乡)      
  160. 龙州镇  南桥镇  上碑镇  口头镇  独羊岗乡  安香乡  只里乡  市同乡  翟营乡  城寨乡  上方乡  玉亭乡  北河乡  上阎庄乡  九口子乡
  161. </行唐县>
  162. <灵寿县 ji="3"> (辖6个镇、9个乡)   
  163. 灵寿镇  青同镇  塔上镇  陈庄镇  慈峪镇  岔头镇  三圣院乡  北洼乡  牛城乡  狗台乡  南寨乡  燕川乡  谭庄乡  寨头乡  南营乡
  164. </灵寿县>

  165. <高邑县 ji="3"><brief>辖1个镇、4个乡</brief>   
  166. 高邑镇  大营乡  中韩乡  万城乡  西富村乡   
  167. </高邑县>
  168. <深泽县 ji="3"><brief>辖2个镇、4个乡</brief>   
  169. 深泽镇  铁杆镇  白庄乡  留村乡  赵八乡  桥头乡     
  170. </深泽县>

  171. <赞皇县 ji="3"><brief>辖2个镇 9个乡</brief>      
  172. 赞皇镇  院头镇  西龙门乡  南邢郭乡  南清河乡  西阳泽乡  土门乡  黄北坪乡  嶂石岩乡  许亭乡  张楞乡
  173. </赞皇县>
  174. <无极县 ji="3"><brief>辖6个镇、4个乡、1个民族乡</brief>   
  175. 无极镇  七汲镇  张段固镇  北苏镇  郭庄镇  大陈镇  高头回族乡  郝庄乡  东侯坊乡  里城道乡  南流乡   
  176. </无极县>

  177. <平山县 ji="3"> (辖12个镇、11个乡)   
  178. 平山镇  东回舍镇  温塘镇  南甸镇  岗南镇  古月镇  下槐镇  孟家庄镇  小觉镇  蛟潭庄镇  西柏坡镇  下口镇  西大吾乡  上三汲乡  两河乡  东王坡乡  苏家庄乡  宅北乡  北治乡  上观音堂乡  杨家桥乡  营里乡  合河口乡
  179. </平山县>
  180. <元氏县 ji="3"> (辖6个镇、9个乡)   
  181. 槐阳镇  宋曹镇  南因镇  殷村镇  姬村镇  南佐镇  东张乡  苏阳乡  赵同乡  北褚乡  马村乡  北正乡  苏村乡  前仙乡  黑水河乡
  182. </元氏县>

  183. <赵县 ji="3"><brief>辖7个镇、4个乡</brief>   
  184. 赵州镇  范庄镇  北王里镇  新寨店镇  韩村镇  南柏舍镇  沙河店镇  前大章乡  谢庄乡  高村乡  王西章乡
  185. </赵县>

  186. </石家庄市>

  187. <唐山市 ji="2"><brief>辖6个市辖区、6个县,代管2个县级市。共35个街道、119个镇、58个乡[其中3个民族乡]</brief>
  188. <路北区 ji="3"><brief>辖11个街道、1个乡</brief>  
  189. 乔屯街道  文化路街道  钓鱼台街道  东新村街道  缸窑街道  机场路街道  河北路街道  龙东街道  大里街道  光明街道  唐山市高新技术开发区街道  果园乡  
  190. </路北区>

  191. <路南区 ji="3"><brief>辖7个街道、1个乡</brief>  
  192. 友谊里街道  学院南路街道  广场街道  永红桥街道  小山街道  文化北后街街道  钱家营矿区街道  女织寨乡  
  193. </路南区>
  194. <古冶区 ji="3"><brief>辖6个街道、5个乡</brief>  
  195. 林西街道  唐家庄街道  古冶街道  赵各庄街道  吕家坨街道  南范各庄街道  卑家店乡  王辇庄乡  习家套乡  大庄坨乡  范各庄乡  
  196. </古冶区>

  197. <开平区 ji="3"><brief>辖5个街道、2个镇、4个乡</brief>  
  198. 马家沟街道  开平街道  税务庄街道  陡电街道  荆各庄矿区街道  开平镇  栗园镇  越河乡  双桥乡  郑庄子乡  洼里乡  
  199. </开平区>
  200. <丰南区 ji="3"><brief>辖1个街道、12个镇、4个乡</brief>  
  201. 胥各庄街道  丰南镇  稻地镇  小集镇  黄各庄镇  西葛镇  大新庄镇  钱营镇  唐坊镇  王兰庄镇  柳树瞿阝镇  黑沿子镇  滨海镇  大齐各庄乡  南孙庄乡  东田庄乡  尖字沽乡
  202. </丰南区>

  203. <丰润区 ji="3"><brief>辖3个街道、18个镇、5个乡</brief>  
  204. 太平路街道  燕山路街道  浭阳街道  丰润镇  老庄子镇  任各庄镇  左家坞镇  泉河头镇  王官营镇  火石营镇  韩城镇  岔河镇  新军屯镇  小张各庄镇  丰登坞镇  李钊庄镇  白官屯镇  石各庄镇  沙流河镇  七树庄镇  杨官林镇  姜家营乡  欢喜庄乡  银城铺乡  刘家营乡  常庄乡  
  205. </丰润区>
  206. <遵化市 ji="3"><brief>辖13个镇、9个乡、3个民族乡</brief>  
  207. 遵化镇  堡子店镇  马兰峪镇  平安城镇  东新庄镇  新店子镇  党峪镇  地北头镇  东旧寨镇  铁厂镇  苏家洼镇  建明镇  石门镇  崔家庄乡  西留村乡  西下营乡  汤泉乡  兴旺寨乡  东陵乡  刘备寨乡  团瓢庄乡  娘娘庄乡  西三里乡  侯家寨乡  小厂乡
  208. </遵化市>

  209. <迁安市 ji="3"><brief>辖12个镇、7个乡</brief>  
  210. 建昌营镇  马兰庄镇  杨店子镇  赵店子镇  野鸡坨镇  大崔庄镇  木厂口镇  沙河驿镇  夏官营镇  杨各庄镇  蔡园镇  迁安镇  五重安乡  闫家店乡  大五里乡  太平庄乡  上射雁庄乡  彭店子乡  扣庄乡  
  211. </迁安市>
  212. <滦县 ji="3"><brief>辖12个镇</brief>  
  213. 滦州镇  响堂镇  东安各庄镇  雷庄镇  茨榆坨镇  榛子镇  杨柳庄镇  油榨镇  古马镇  小马庄镇  九百户镇  王店子镇  
  214. </滦县>

  215. <滦南县 ji="3"><brief>辖17个镇</brief>  
  216. 倴城镇  胡各庄镇  长宁镇 柏各庄镇 扒齿港镇 安各庄镇 青坨营 马城镇  姚王庄镇  东黄坨镇 南堡镇 柳赞镇 程庄镇 坨里镇 司各庄镇 宋道口镇 方各庄镇
  217. </滦南县>
  218. <乐亭县 ji="3"><brief>辖1个街道、9个镇、5个乡</brief>  
  219. 乐安街道  乐亭镇  汤家河镇  胡家坨镇  王滩镇  闫各庄镇  马头营镇  新寨镇  汀流河镇  姜各庄镇  毛庄乡  庞各庄乡  大相各庄乡  古河乡  中堡王庄乡  
  220. </乐亭县>

  221. <迁西县 ji="3"><brief>辖1个街道、9个镇、8个乡</brief>  
  222. 栗乡街道  兴城镇  金厂峪镇  洒河桥镇  太平寨镇  罗家屯镇  东荒峪镇  新集镇  三屯营镇  滦阳镇  白庙子乡  上营乡  汉儿庄乡  渔户寨乡  旧城乡  尹庄乡  东莲花院乡  新庄子乡  
  223. </迁西县>
  224. <玉田县 ji="3"><brief>辖14个镇、6个乡</brief>
  225. 玉田镇  亮甲店镇  鸦鸿桥镇  窝洛沽镇  石臼窝镇  虹桥镇  散水头镇  林南仓镇  林西镇  杨家板桥镇  彩亭桥镇  孤树镇  大安镇  唐自头镇  郭家屯乡  林头屯乡  杨家套乡  潮洛窝乡  陈家铺乡  郭家桥乡  
  226. </玉田县>

  227. <唐海县 ji="3"><brief>辖1个镇</brief>
  228. 唐海镇  一农场  三农场  四农场  五农场  六农场  七农场  八农场  九农场  十农场  十一农场  八里滩养殖场  十里海养殖场

  229. </唐海县>
  230. </唐山市>

  231. </河北省>

  232. </中国>
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10张SACC2017门票等你来拿~

在数字化转型时代,云已成为万物智能的数字化大脑。而随着大数据应用、人工智能、移动互联网等技术的飞速发展,“智慧 +” 的概念正在深入到各行各业,提升企业效率,释放商业潜能,创造全新机遇。作为国内顶级技术盛会之一,2017 中国系统架构师大会(SACC2017)将于 10 月 19-21 日在北京新云南皇冠假日酒店震撼来袭。今年,大会以 “云智未来” 为主题,云集国内外顶级专家,围绕云计算、人工智能、大数据、移动互联网、产业应用等热点领域展开技术探讨与交流。本届大会共设置 2 大主会场,18 个技术专场;邀请来自互联网、金融、制造业、电商等多个领域,100 余位技术专家及行业领袖来分享他们的经验;并将吸引 4000 + 人次的系统运维、架构师及 IT 决策人士参会,为他们提供最具价值的交流平台。
----------------------------------------
优惠时间:2017年10月19日前

活动链接>>
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802020122
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP