Разбор XML-сущности с помощью python xml.sax - PullRequest
1 голос
/ 15 июня 2011

Синтаксический анализ XML на python с использованием xml.sax, но мой код не может перехватить сущности.Почему skippedEntity () или resolEntity () не сообщают следующее:

import os
import cStringIO
import xml.sax
from xml.sax.handler import ContentHandler,EntityResolver,DTDHandler

#Class to parse and run test XML files
class TestHandler(ContentHandler,EntityResolver,DTDHandler):

    #SAX handler - Entity resolver
    def resolveEntity(self,publicID,systemID):
        print "TestHandler.resolveEntity: %s  %s" % (publicID,systemID)

    def skippedEntity(self, name):
        print "TestHandler.skippedEntity: %s" % (name)

    def unparsedEntityDecl(self,publicID,systemID,ndata):
        print "TestHandler.unparsedEntityDecl: %s  %s" % (publicID,systemID)

    def startElement(self,name,attrs):
        # name = string.lower(name)
        summary = '' + attrs.get('summary','')
        arg = '' + attrs.get('arg','')
        print 'TestHandler.startElement(), %s : %s (%s)' % (name,summary,arg)


def run(xml_string):
    try:
        parser = xml.sax.make_parser()
        stream = cStringIO.StringIO(xml_string)

        curHandler = TestHandler()
        parser.setContentHandler(curHandler)
        parser.setDTDHandler( curHandler )
        parser.setEntityResolver( curHandler )

        parser.parse(stream)
        stream.close()
    except (xml.sax.SAXParseException), e:
        print "*** PARSER error: %s" % e;

def main():
    try:
        XML = "<!DOCTYPE page[ <!ENTITY num 'foo'> ]><test summary='step: &num;'>Entity: &not;</test>"
        run(XML)
    except Exception, e:
      print 'FATAL ERROR: %s' % (str(e))

if __name__== '__main__':
    main()

При запуске все, что я вижу, это:

 TestHandler.startElement(), step: foo ()
 *** PARSER error: <unknown>:1:36: undefined entity

Почему я не вижу resolEntityпечать для # или пропущенной записи печать для ¬?

Ответы [ 2 ]

1 голос
/ 20 июня 2011

Вот модифицированная версия вашей программы, которая, я надеюсь, имеет смысл.Он демонстрирует случай, когда вызываются все TestHandler методы.

import StringIO
import xml.sax
from xml.sax.handler import ContentHandler

# Inheriting from EntityResolver and DTDHandler is not necessary
class TestHandler(ContentHandler):

    # This method is only called for external entities. Must return a value. 
    def resolveEntity(self, publicID, systemID):
        print "TestHandler.resolveEntity(): %s %s" % (publicID, systemID)
        return systemID

    def skippedEntity(self, name):
        print "TestHandler.skippedEntity(): %s" % (name)

    def unparsedEntityDecl(self, name, publicID, systemID, ndata):
        print "TestHandler.unparsedEntityDecl(): %s %s" % (publicID, systemID)

    def startElement(self, name, attrs):
        summary = attrs.get('summary', '')
        print 'TestHandler.startElement():', summary

def main(xml_string):
    try:
        parser = xml.sax.make_parser()
        curHandler = TestHandler()
        parser.setContentHandler(curHandler)
        parser.setEntityResolver(curHandler)
        parser.setDTDHandler(curHandler)

        stream = StringIO.StringIO(xml_string)
        parser.parse(stream)
        stream.close()
    except xml.sax.SAXParseException, e:
        print "*** PARSER error: %s" % e

XML = """<!DOCTYPE test SYSTEM "test.dtd">
<test summary='step: &num;'>Entity: &not;</test>
"""

main(XML)

test.dtd содержит:

<!ENTITY num "FOO">
<!ENTITY pic SYSTEM 'bar.gif' NDATA gif>

Вывод:

TestHandler.resolveEntity(): None test.dtd
TestHandler.unparsedEntityDecl(): None bar.gif
TestHandler.startElement(): step: FOO
TestHandler.skippedEntity(): not

Добавление

Насколько я могу судить, skippedEntity вызывается только при использовании внешнего DTD (по крайней мере, я не могу придумать контрпример;было бы хорошо, если бы документация была немного понятнее).

Адам сказал в своем ответе, что resolveEntity вызывается только для внешних DTD.Но это не совсем так.resolveEntity также вызывается при обработке ссылки на внешний объект, который объявлен во внутреннем или внешнем подмножестве DTD.Например:

<!DOCTYPE test [
<!ENTITY num SYSTEM "bar.txt">
]>

, где содержимое bar.txt может быть, скажем, FOO.В этом случае невозможно ссылаться на сущность в значении атрибута .

1 голос
/ 18 июня 2011

Мне кажется, что resolEntity и skippedEntity вызываются только для внешних DTD. Я получил это на работу, изменив XML.

XML = """<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE test SYSTEM "external.dtd" >
<test summary='step: &foo; &bar;'>Entity: &not;</test>
"""

external.dtd содержит два простых объявления сущностей.

<!ENTITY foo "bar">
<!ENTITY bar "foo">

Также я избавился от resolEntity.

Это выводит -

TestHandler.startElement(), test : step: bar foo ()
TestHandler.skippedEntity: not

Надеюсь, это поможет.

...