Разбор XML-сущности с помощью python xml.sax

1

Анализ XML с помощью python с помощью xml.sax, но мой код не может поймать Entities. Почему в skidEntity() или 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

Почему я не вижу printEventity для & num; или пропущенная запись для печати не?;

Теги:
parsing
sax

2 ответа

1
Лучший ответ

Я думаю, что resolveEntity и 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">

Кроме того, я избавился от resolveEntity.

Эти выходы -

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

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

  • 0
    Спасибо, я не понял, что DTD должен быть внешним.
1

Вот измененная версия вашей программы, которая, на мой взгляд, имеет смысл. Он демонстрирует случай, когда вызываются все методы 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. В этом случае невозможно указать объект в значении атрибута.

  • 0
    Благодарю. Был бы способ получить skippedEntity для вызова, если бы не было внешнего DTD?
  • 0
    @Jonathan: я обновил свой ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню