Синтаксический анализ XML-сущности с помощью python xml.sax
Синтаксический анализ 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: #'>Entity: ¬</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 ответа
Я думаю, что resolEntity и skippedEntity вызываются только для внешних DTD. Я получил это на работу, изменив XML.
XML = """<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE test SYSTEM "external.dtd" >
<test summary='step: &foo; &bar;'>Entity: ¬</test>
"""
External.dtd содержит два простых объявления сущностей.
<!ENTITY foo "bar">
<!ENTITY bar "foo">
Также я избавился от resolEntity.
Это выводит -
TestHandler.startElement(), test : step: bar foo ()
TestHandler.skippedEntity: not
Надеюсь это поможет.
Вот модифицированная версия вашей программы, которая, я надеюсь, имеет смысл. Это демонстрирует случай, когда все 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: #'>Entity: ¬</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
, В этом случае невозможно сослаться на сущность в значении атрибута.