首頁 後端開發 Python教學 详解Python中DOM方法的动态性

详解Python中DOM方法的动态性

Jun 10, 2016 pm 03:15 PM
python

文档对象模型

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

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

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

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

2015411151828304.gif (368×205)

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

将 HTML 转换成 XML

有效的 HTML 几乎就是有效的 XML,但又不完全相同。这里有两个主要的差异,XML 标记是区分大小写的,并且所有 XML 标记都需要一个显式的结束符号(作为结束标记,而这对于某些 HTML 标记是可选的;例如: 详解Python中DOM方法的动态性 )。使用 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 列表执行的任何其它操作一样简单。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

vs code 可以在 Windows 8 中運行嗎 vs code 可以在 Windows 8 中運行嗎 Apr 15, 2025 pm 07:24 PM

VS Code可以在Windows 8上運行,但體驗可能不佳。首先確保系統已更新到最新補丁,然後下載與系統架構匹配的VS Code安裝包,按照提示安裝。安裝後,注意某些擴展程序可能與Windows 8不兼容,需要尋找替代擴展或在虛擬機中使用更新的Windows系統。安裝必要的擴展,檢查是否正常工作。儘管VS Code在Windows 8上可行,但建議升級到更新的Windows系統以獲得更好的開發體驗和安全保障。

visual studio code 可以用於 python 嗎 visual studio code 可以用於 python 嗎 Apr 15, 2025 pm 08:18 PM

VS Code 可用於編寫 Python,並提供許多功能,使其成為開發 Python 應用程序的理想工具。它允許用戶:安裝 Python 擴展,以獲得代碼補全、語法高亮和調試等功能。使用調試器逐步跟踪代碼,查找和修復錯誤。集成 Git,進行版本控制。使用代碼格式化工具,保持代碼一致性。使用 Linting 工具,提前發現潛在問題。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

See all articles