2011-08-30 22 views
17

私はパースするためのスーパーシンプルなXMLファイルのセットを持っています...しかし...彼らはカスタム定義エンティティを使用します。これらを文字にマップする必要はありませんが、それぞれを解析して処理したいと考えています。たとえば:未知のXMLエンティティを解析するためのPython ElementTreeサポート?

<Style name="admin-5678"> 
    <Rule> 
     <Filter>[admin_level]='5'</Filter> 
     &maxscale_zoom11; 
    </Rule> 
</Style> 

ありXMLParserのは、限られたエンティティをサポートしているhttp://effbot.org/elementtree/elementtree-xmlparser.htmで食欲をそそるヒントがあるが、私は言及した方法を見つけることができない、すべてがエラーを与える:

どのように依存
#!/usr/bin/python 
    ## 
    ## Where's the entity support as documented at: 
    ## http://effbot.org/elementtree/elementtree-xmlparser.htm 
    ## In Python 2.7.1+ ? 
    ## 
    from pprint  import pprint 
    from xml.etree import ElementTree 
    from cStringIO import StringIO 

    parser = ElementTree.ElementTree() 
    #parser.entity["maxscale_zoom11"] = unichr(160) 
    testf = StringIO('<foo>&maxscale_zoom11;</foo>') 
    tree = parser.parse(testf) 
    #tree = parser.parse(testf,"XMLParser") 
    for node in tree.iter('foo'): 
     print node.text 

コメントを調整できます:

xml.etree.ElementTree.ParseError: undefined entity: line 1, column 5 

または

XMLは OpenStreetMapのMAPNIKプロジェクトからである好奇心が強い人のために

または

AttributeError: 'str' object has no attribute 'feed'   

+0

おそらく関連する質問:その場合には実体が実際に定義されているためhttp://stackoverflow.com/questions/2524299/entity-references-and-lxml – unutbu

+0

、関係ありません。エンティティ定義を削除すると、私の質問に戻ります。 – Bryce

+0

fyi - 誰かが/ usr/bin/pythonを/ usr/bin/env pythonに修正したい場合があります。ほとんどのシステムではshebang行が間違っているからです。 –

答えて

11

これがElementTreeのバグかどうか分かりませんが、過去の方法と同じように、expatパーサーでUseForeignDTD(True)を呼び出す必要があります。

それは少しハックですが、あなたは)、ElementTree.Parserの独自のインスタンスを作成することがxml.parsers.expatのインスタンスの上でメソッドを呼び出すと、その後ElementTree.parse(に渡すことでこれを行うことができます。

これは、 "moo_1"

を出力

from xml.etree import ElementTree 
from cStringIO import StringIO 

class AllEntities: 
    def __getitem__(self, key): 
     #key is your entity, you can do whatever you want with it here 
     return key 

testf = StringIO('<foo>&moo_1;</foo>') 

parser = ElementTree.XMLParser() 
parser.parser.UseForeignDTD(True) 
parser.entity = AllEntities() 

etree = ElementTree.ElementTree() 

tree = etree.parse(testf, parser=parser) 

for node in tree.iter('foo'): 
    print node.text 

from xml.etree import ElementTree 
from cStringIO import StringIO 


testf = StringIO('<foo>&moo_1;</foo>') 

parser = ElementTree.XMLParser() 
parser.parser.UseForeignDTD(True) 
parser.entity['moo_1'] = 'MOOOOO' 

etree = ElementTree.ElementTree() 

tree = etree.parse(testf, parser=parser) 

for node in tree.iter('foo'): 
    print node.text 

これは "MOOOOO"

またはマッピングインタフェースを使用して出力します0

さらに複雑な修正は、ElementTree.XMLParserをサブクラス化して修正することです。

+0

あなたが言っているように少し腹が立っていますが、ありがとう。エンティティ(例:&moo_2)を事前に定義する必要がないようにする方法はありますか? – Bryce

+0

@Bryce:事前定義されているのはエンティティのポイントですか、いいえ?それにもかかわらず、あなたはあなたの辞書のようなオブジェクトに 'parser.entity'を設定することができます。簡単な例として、 'parser.entity = collections 'を実行することができます。すべての未定義のエンティティを空の文字列に置き換えるためには、defaultdict(str) 'を使用します。 – Steven

+0

@ Stevenのコメントにフォローアップするには、マッピングインターフェイスを実装して、キーで必要な操作を行うこともできます。私はその簡単な例を示すために私の答えを編集しました。 – cnelson

3

@cnelsonが既にコメントで指摘したように、ここで選択したソリューションは、私はついにそれが働いてしまったのPython 3に

を動作しません。このQ&Aから引用しました。

this postからインスパイアされていますが、入力された生のHTMLコンテンツにXML定義を追加するだけで、ElementTreeはそのまま使用できます。

これは、Python 2.6,2.7,3.3,3.4の両方で機能します。

import xml.etree.ElementTree as ET 

html = '''<html> 
    <div>Some reasonably well-formed HTML content.</div> 
    <form action="login"> 
    <input name="foo" value="bar"/> 
    <input name="username"/><input name="password"/> 

    <div>It is not unusual to see &nbsp; in an HTML page.</div> 

    </form></html>''' 

magic = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [ 
      <!ENTITY nbsp ' '> 
      ]>''' # You can define more entities here, if needed 

et = ET.fromstring(magic + html) 
関連する問題