2009-10-20 15 views
14

Tôi đang sử dụng Python (minidom) để phân tích một tập tin XML in một cấu trúc phân cấp trông giống như thế này (thụt đầu dòng được sử dụng ở đây để hiển thị các mối quan hệ thứ bậc đáng kể):XML Parsing với Python và minidom

My Document 
Overview 
    Basic Features 
    About This Software 
     Platforms Supported 

Thay vào đó, chương trình lặp lại nhiều lần trên các nút và tạo ra các nút sau, in các nút trùng lặp. (Nhìn vào danh sách nút tại mỗi lần lặp, nó rõ ràng lý do tại sao nó thực hiện điều này nhưng tôi dường như không thể tìm thấy một cách để có được danh sách nút Tôi đang tìm kiếm.)

My Document 
Overview 
Basic Features 
About This Software 
Platforms Supported 
Basic Features 
About This Software 
Platforms Supported 
Platforms Supported 

Đây là nguồn XML file:

<?xml version="1.0" encoding="UTF-8"?> 
<DOCMAP> 
    <Topic Target="ALL"> 
     <Title>My Document</Title> 
    </Topic> 
    <Topic Target="ALL"> 
     <Title>Overview</Title> 
     <Topic Target="ALL"> 
      <Title>Basic Features</Title> 
     </Topic> 
     <Topic Target="ALL"> 
      <Title>About This Software</Title> 
      <Topic Target="ALL"> 
       <Title>Platforms Supported</Title> 
      </Topic> 
     </Topic> 
    </Topic> 
</DOCMAP> 

dưới đây là chương trình Python:

import xml.dom.minidom 
from xml.dom.minidom import Node 

dom = xml.dom.minidom.parse("test.xml") 
Topic=dom.getElementsByTagName('Topic') 
i = 0 
for node in Topic: 
    alist=node.getElementsByTagName('Title') 
    for a in alist: 
     Title= a.firstChild.data 
     print Title 

tôi có thể sửa chữa vấn đề bằng cách không làm tổ yếu tố '' được, bằng cách thay đổi tên cấp dưới chủ đề để một cái gì đó như 'SubTopic1' và ' SubTopic2 '. Nhưng, tôi muốn tận dụng lợi thế của cấu trúc phân cấp XML dựng sẵn mà không cần các tên phần tử khác nhau; có vẻ như tôi nên có thể lồng ghép các yếu tố 'Chủ đề' và rằng phải có một cách nào đó để biết 'Chủ đề' cấp độ nào mà tôi đang xem xét.

Tôi đã thử một số hàm XPath khác nhau mà không thành công nhiều.

+0

Nếu bạn muốn đầu ra của một đầu tiên bạn chỉ có thể in văn bản ra của mỗi yếu tố - Tôi không rõ ràng như thế nào structuting ảnh hưởng đến sản lượng truy nã – Mark

Trả lời

8

getElementsByTagName là đệ quy, bạn sẽ nhận được tất cả hậu duệ có tên thẻ phù hợp. Vì Chủ đề của bạn chứa các Chủ đề khác cũng có Tiêu đề, cuộc gọi sẽ nhận được các Tiêu đề từ dưới xuống nhiều lần.

Nếu bạn muốn hỏi cho tất cả trẻ em chỉ trực tiếp phù hợp, và bạn không có XPath có sẵn, bạn có thể viết một bộ lọc đơn giản, Eg .:

def getChildrenByTagName(node, tagName): 
    for child in node.childNodes: 
     if child.nodeType==child.ELEMENT_NODE and (tagName=='*' or child.tagName==tagName): 
      yield child 

for topic in document.getElementsByTagName('Topic'): 
    title= list(getChildrenByTagName('Title'))[0]   # or just get(...).next() 
    print title.firstChild.data 
+0

Cảm ơn đã nỗ lực. Nó không hiệu quả nhưng nó đã cho tôi một số ý tưởng. Các tác phẩm sau (cùng ý tưởng chung; FWIW, nút loại là ELEMENT_NODE): nhập xml.dom.minidom từ nhập khẩu xml.dom.minidom Node dom = xml.dom.minidom.parse ("docmap.xml ") def getChildrenByTitle (nút): cho con trong node.childNodes: nếu child.localName == 'Title': năng suất con Topic = dom.getElementsByTagName ('Chủ đề') cho nút trong chủ đề: alist = getChildrenByTitle (nút) cho một lượt truy cập: # Tiêu đề = a.firstChild.data Tiêu đề = a.childNodes [0] .nodeValue in Tiêu đề – hWorks

+0

Rất tiếc, ý tôi là ELEMENT không TEXT! doh, cố định – bobince

7

Hãy để tôi đưa bình luận rằng đây .. .

Cảm ơn bạn đã thử. Nó không hiệu quả nhưng nó đã cho tôi một số ý tưởng. Các công trình sau đây (ý tưởng chung cùng; FWIW, các nodeType là ELEMENT_NODE):

import xml.dom.minidom 
from xml.dom.minidom import Node 

dom = xml.dom.minidom.parse("docmap.xml") 

def getChildrenByTitle(node): 
    for child in node.childNodes: 
     if child.localName=='Title': 
      yield child 

Topic=dom.getElementsByTagName('Topic') 
for node in Topic: 
    alist=getChildrenByTitle(node) 
    for a in alist: 
#  Title= a.firstChild.data 
     Title= a.childNodes[0].nodeValue 
     print Title 
+0

Tôi sẽ gọi hàm getTitle (hoặc 'get_title') và không trả về tất cả các phần tử Title con ngay lập tức, nhưng chỉ là phần tử đầu tiên (vì chỉ có một tiêu đề cho mỗi đứa trẻ). –

+0

Có lẽ đây là những gì tôi không nhận được. Tôi muốn các chức danh của tất cả trẻ em ngay lập tức. Có lẽ một tên tốt hơn sẽ là getTitlesOfChildren. – hWorks

3

Bạn có thể sử dụng máy phát điện sau để chạy qua danh sách và có được danh hiệu với mức độ thụt đầu dòng:

def f(elem, level=-1): 
    if elem.nodeName == "Title": 
     yield elem.childNodes[0].nodeValue, level 
    elif elem.nodeType == elem.ELEMENT_NODE: 
     for child in elem.childNodes: 
      for e, l in f(child, level + 1): 
       yield e, l 

Nếu bạn thử nghiệm nó với tập tin của bạn:

import xml.dom.minidom as minidom 
doc = minidom.parse("test.xml") 
list(f(doc)) 

bạn sẽ nhận được một danh sách với các bộ dữ liệu sau đây:

(u'My Document', 1), 
(u'Overview', 1), 
(u'Basic Features', 2), 
(u'About This Software', 2), 
(u'Platforms Supported', 3) 

Nó chỉ là một ý tưởng cơ bản để được tinh chỉnh tất nhiên. Nếu bạn chỉ muốn không gian ngay từ đầu bạn có thể mã trực tiếp trong trình tạo, mặc dù với mức độ bạn linh hoạt hơn. Bạn cũng có thể phát hiện mức đầu tiên tự động (ở đây nó chỉ là một công việc nghèo của việc khởi tạo mức đến -1 ...).

+0

Chính xác những gì tôi đã cố gắng làm cả ngày trước khi đến máy phát điện. Cảm ơn nhiều. – hWorks

1

chức năng Recusive:

import xml.dom.minidom 

def traverseTree(document, depth=0): 
    tag = document.tagName 
    for child in document.childNodes: 
    if child.nodeType == child.TEXT_NODE: 
     if document.tagName == 'Title': 
     print depth*' ', child.data 
    if child.nodeType == xml.dom.Node.ELEMENT_NODE: 
     traverseTree(child, depth+1) 

filename = 'sample.xml' 
dom = xml.dom.minidom.parse(filename) 
traverseTree(dom.documentElement) 

xml của bạn:

<?xml version="1.0" encoding="UTF-8"?> 
<DOCMAP> 
    <Topic Target="ALL"> 
     <Title>My Document</Title> 
    </Topic> 
    <Topic Target="ALL"> 
     <Title>Overview</Title> 
     <Topic Target="ALL"> 
      <Title>Basic Features</Title> 
     </Topic> 
     <Topic Target="ALL"> 
      <Title>About This Software</Title> 
      <Topic Target="ALL"> 
       <Title>Platforms Supported</Title> 
      </Topic> 
     </Topic> 
    </Topic> 
</DOCMAP> 

đầu ra mong muốn của bạn:

$ python parse_sample.py 
     My Document 
     Overview 
      Basic Features 
      About This Software 
       Platforms Supported 
2

Tôi nghĩ rằng có thể giúp

import os 
import sys 
import subprocess 
import base64,xml.dom.minidom 
from xml.dom.minidom import Node 
f = open("file.xml",'r') 
data = f.read() 
i = 0 
doc = xml.dom.minidom.parseString(data) 
for topic in doc.getElementsByTagName('Topic'): 
    title= doc.getElementsByTagName('Title')[i].firstChild.nodeValue 
    print title 
    i +=1 

Output:

My Document 
Overview 
Basic Features 
About This Software 
Platforms Supported