新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> DTD, XML Schema(XMLS), RELAX NG
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 DTD/XML Schema 』 → 可爱的 Python:DOM 的动态性 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 6733 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: 可爱的 Python:DOM 的动态性 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     anchen0617 帅哥哟,离线,有人找我吗?双子座1983-6-17
      
      
      威望:5
      等级:大二(研究C++)
      文章:281
      积分:3413
      门派:XML.ORG.CN
      注册:2004/10/17

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给anchen0617发送一个短消息 把anchen0617加入好友 查看anchen0617的个人资料 搜索anchen0617在『 DTD/XML Schema 』的所有贴子 访问anchen0617的主页 引用回复这个贴子 回复这个贴子 查看anchen0617的博客楼主
    发贴心情 可爱的 Python:DOM 的动态性

    什么是 Python?什么是 XML?
    Python 是由 Guido van Rossum 开发的可免费获得的高级解释型语言。其语法简单易懂,而其面向对象的语义功能强大,却又灵活随意。Python 几乎适用于每一种计算机平台,并且在平台间具有很强的可移植性。

    XML 是“标准通用标记语言”(SGML) 的一种简化版本。通过一种特殊的文档类型 HTML,您也许非常熟悉 SGML。XML 文档与 HTML 一样,都是由散布于文本中的、以尖括号括起的标记确定其结构的文本组成的。但 XML 包含了许多系统标记,它们使 XML 可以用于多种用途:杂志文章和用户文档、结构化数据的文件(如 CSV 和 EDI 文件)、程序间中间通信的消息、建筑图纸(如 CAD 格式)以及许多其它用途。可以创建一组标记,以生成任何一种您想要表达的结构化信息,这就是为什么 XML 会逐渐流行,成为表示各种信息的公共标准。

    文档对象模型
    xml.dom 模块对于 Python 程序员来说,可能是使用 XML 文档时功能最强大的工具。不幸的是,XML-SIG 提供的文档目前来说还比较少。W3C 语言无关的 DOM 规范填补了这方面的部分空白。但 Python 程序员最好有一个特定于 Python 语言的 DOM 的快速入门指南。本文旨在提供这样一个指南。在 上一篇专栏文章中,某些样本中使用了样本 quotations.dtd 文件,并且这些文件可以与本文中的代码样本档案文件一起使用。


    有必要了解 DOM 的确切含义。这方面,正式解释非常好:

    “文档对象模型”是平台无关和语言无关的接口,它允许程序和脚本动态访问和更新文档的内容、结构和样式。可以进一步处理文档,而处理的结果也可以合并到已显示的页面中。(万维网联盟 DOM 工作组)


    DOM 将 XML 文档转换成树 -- 或森林 -- 表示。万维网联盟 (W3C) 规范给出了一个 HTML 表的 DOM 版本作为例子。

    如上图所示,DOM 从一个更加抽象的角度定义了一组可以遍历、修剪、改组、输出和操作树的方法,而这种方法要比 XML 文档的线性表示更为便利。

    将 HTML 转换成 XML
    有效的 HTML 几乎就是有效的 XML,但又不完全相同。这里有两个主要的差异,XML 标记是区分大小写的,并且所有 XML 标记都需要一个显式的结束符号(作为结束标记,而这对于某些 HTML 标记是可选的;例如:<img src="X.png" />)。使用 xml.dom 的一个简单示例就是使用 HtmlBuilder() 类将 HTML 转换成 XML。

    try_dom1.py

    """Convert a valid HTML document to XML
       USAGE: python try_dom1.py < infile.html > outfile.xml
    """
    import sys
    from xml.dom import core
    from xml.dom.html_builder import HtmlBuilder

    # Construct an HtmlBuilder object and feed the data to it
    b = HtmlBuilder()
    b.feed(sys.stdin.read())

    # Get the newly-constructed document object
    doc = b.document

    # Output it as XML
    print doc.toxml()

    HtmlBuilder() 类很容易实现它继承的部分基本 xml.dom.builder 模板的功能,它的源码值得研究。然而,即使我们自己实现了模板功能,DOM 程序的轮廓还是相似的。在一般情况下,我们将用一些方法构建一个 DOM 实例,然后对该实例进行操作。DOM 实例的 .toxml() 方法是一种生成 DOM 实例的字符串表示的简单方法(在以上的情况中,只要在生成后将它打印出来)。

    将 Python 对象转换成 XML
    Python 程序员可以通过将任意 Python 对象导出为 XML 实例来实现相当多的功能和通用性。这就允许我们以习惯的方式来处理 Python 对象,并且可以选择最终是否使用实例属性作为生成 XML 中的标记。只需要几行(从 building.py 示例派生出),我们就可以将 Python“原生”对象转换成 DOM 对象,并对包含对象的那些属性执行递归处理。

    try_dom2.py

    """Build a DOM instance from scratch, write it to XML
       USAGE: python try_dom2.py > outfile.xml
    """
    import types
    from xml.dom import core
    from xml.dom.builder import Builder

    # Recursive function to build DOM instance from Python instance
    defobject_convert(builder, inst):
        # Put entire object inside an elem w/ same name as the class.
        builder.startElement(inst.__class__.__name__)

        for attr in inst.__dict__.keys():
            if attr[0] == '_':      # Skip internal attributes
                continue
            value = getattr(inst, attr)
            if type(value) == types.InstanceType:
                # Recursively process subobjects
                object_convert(builder, value)
            else:
                # Convert anything else to string, put it in an element
                builder.startElement(attr)
                builder.text(str(value))
                builder.endElement(attr)

        builder.endElement(inst.__class__.__name__)

    if __name__ == '__main__':
        # Create container classes
        classquotations: pass
        classquotation: pass

        # Create an instance, fill it with hierarchy of attributes
        inst = quotations()
        inst.title = "Quotations file (not quotations.dtd conformant)"
        inst.quot1 = quot1 = quotation()
        quot1.text = """'"is not a quine" is not a quine' is a quine"""
        quot1.source = "Joshua Shagam, kuro5hin.org"
        inst.quot2 = quot2 = quotation()
        quot2.text = "Python is not a democracy. Voting doesn't help. "+\
                     "Crying may..."
        quot2.source = "Guido van Rossum, comp.lang.python"

        # Create the DOM Builder
        builder = Builder()
        object_convert(builder, inst)
        print builder.document.toxml()

    函数 object_convert() 有一些限制。例如,不可能用以上的过程生成符合 XML 文档的 quotations.dtd:#PCDATA 文本不能直接放到 quotation 类中,而只能放到类的属性中(如 .text)。一个简单的变通方法就是让 object_convert() 以特殊方式处理一个带有名称的属性,例如 .PCDATA。可以用各种方法使对 DOM 的转换变得更巧妙,但该方法的妙处在于我们可以从整个 Python 对象开始,以简明的方式将它们转换成 XML 文档。

    还应值得注意的是在生成的 XML 文档中,处于同一个级别的元素没有什么明显的顺序关系。例如,在作者的系统中使用特定版本的 Python,源码中定义的第二个 quotation 在输出中却第一个出现。但这种顺序关系在不同的版本和系统之间会改变。Python 对象的属性并不是按固定顺序排列的,因此这种特性就具有意义。对于与数据库系统相关的数据,我们希望它们具有这种特性,但是对于标记为 XML 的文章却显然不希望具有这种特性(除非我们想要更新 William Burroughs 的 "cut-up" 方法)。

    将 XML 文档转换成 Python 对象
    从 XML 文档生成 Python 对象就像其逆向过程一样简单。在多数情况下,用 xml.dom 方法就可以了。但在某些情况下,最好使用与处理所有“类属”Python 对象相同的技术来处理从 XML 文档生成的对象。例如,在以下的代码中,函数 pyobj_printer() 也许是已经用来处理任意 Python 对象的函数。

    try_dom3.py

    """Read in a DOM instance, convert it to a Python object
    """
    from xml.dom.utils import FileReader

    classPyObject: pass

    defpyobj_printer(py_obj, level=0):
        """Return a "deep" string description of a Python object"""
        from string import join, split
        import types
        descript = ''
        for membname in dir(py_obj):
            member = getattr(py_obj,membname)
            if type(member) == types.InstanceType:
                descript = descript + (' '*level) + '{'+membname+'}\n'
                descript = descript + pyobj_printer(member, level+3)
            elif type(member) == types.ListType:
                descript = descript + (' '*level) + '['+membname+']\n'
                for i in range(len(member)):
                    descript = descript+(' '*level)+str(i+1)+': '+ \
                               pyobj_printer(member[i],level+3)
            else:
                descript = descript + membname+'='
                descript = descript + join(split(str(member)[:50]))+'...\n'
        return descript

    defpyobj_from_dom(dom_node):
        """Converts a DOM tree to a "native" Python object"""
        py_obj = PyObject()
        py_obj.PCDATA = ''
        for node in dom_node.get_childNodes():
            if node.name == '#text':
                py_obj.PCDATA = py_obj.PCDATA + node.value
            elif hasattr(py_obj, node.name):
                getattr(py_obj, node.name).append(pyobj_from_dom(node))
            else:
                setattr(py_obj, node.name, [pyobj_from_dom(node)])
        return py_obj

    # Main test
    dom_obj = FileReader("quotes.xml").document
    py_obj = pyobj_from_dom(dom_obj)
    if __name__ == "__main__":
        print pyobj_printer(py_obj)

    这里的关注焦点应该是函数 pyobj_from_dom(),特别是起实际作用的 xml.dom 方法 .get_childNodes()。在 pyobj_from_dom() 中,我们直接抽取标记之间的所有文本,将它放到保留属性 .PCDATA 中。对于任何遇到的嵌套标记,我们创建一个新属性,其名称与标记匹配,并将一个列表分配给该属性,这样就可以潜在地包含在在父代块中多次出现的标记。当然,使用列表要维护在 XML 文档中遇到的标记的顺序。

    除了使用旧的 pyobj_printer() 类属函数(或者,更复杂和健壮的函数)之外,我们可以使用正常的属性记号来访问 py_obj 的元素。

    Python 交互式会话

    >>> from try_dom3 import *
    >>> py_obj.quotations[0].quotation[3].source[0].PCDATA
    'Guido van Rossum, '

    重新安排 DOM 树
    DOM 的一大优点是它可以让程序员以非线性方式对 XML 文档进行操作。由相匹配的开/关标记括起的每一块都只是 DOM 树中的一个“节点”。当以类似于列表的方式维护节点以保留顺序信息时,则顺序并没有什么特殊之处,也并非不可改变。我们可以轻易地剪下某个节点,嫁接到 DOM 树的另一个位置(如果 DTD 允许,甚至嫁接到另一层上)。或者添加新的节点、删除现有节点,等等。

    try_dom4.py

    """Manipulate the arrangement of nodes in a DOM object
    """
    from try_dom3 import *

    #-- Var 'doc' will hold the single <quotations> "trunk"
    doc = dom_obj.get_childNodes()[0]

    #-- Pull off all the nodes into a Python list
    # (each node is a <quotation> block, or a whitespace text node)
    nodes = []
    while 1:
        try: node = doc.removeChild(doc.get_childNodes()[0])
        except: break
        nodes.append(node)

    #-- Reverse the order of the quotations using a list method
    # (we could also perform more complicated operations on the list:
    # delete elements, add new ones, sort on complex criteria, etc.)
    nodes.reverse()

    #-- Fill 'doc' back up with our rearranged nodes
    for node in nodes:
        # if second arg is None, insert is to end of list
        doc.insertBefore(node, None)

    #-- Output the manipulated DOM
    print dom_obj.toxml()

    如果我们将 XML 文档只看作一个文本文件,或者使用一个面向序列的模块(如 xmllib 或 xml.sax),那么在以上几行中执行对 quotation 节点的重新安排操作将引出一个值得考虑的问题。然而如果使用 DOM,则问题就如同对 Python 列表执行的任何其它操作一样简单。


       收藏   分享  
    顶(1)
      




    ----------------------------------------------
    xml这门语言太好了,我们共同努力吧!!!!!

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2004/11/13 15:02:00
     
     GoogleAdSense双子座1983-6-17
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 DTD/XML Schema 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/3/28 13:19:35

    本主题贴数1,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  可爱的 Python:DOM 的动态性(9683字) - anchen0617,2004年11月13日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    89.844ms