Как разрешить внутренне объявленную ссылку на объект XML с помощью NSXMLParser

У меня есть файл XML, в котором используются внутренне объявленные сущности. Например:

<?xml version="1.0" encoding="UTF-8"?>

...

<!ENTITY my_symbol "my symbol value">

...

<my_element>
    <my_next_element>foo&my_symbol;bar</my_next_element>
</my_element>

...

Используя класс NSXMLParser, как я могу разрешить ссылку на объект my_symbol?

В ходе эксперимента метод делегата parser:foundInternalEntityDeclarationWithName:value: будет вызываться для объявления объекта my_symbol со значением "my symbol value". Затем, когда будет достигнут элемент my_next_element, NSXMLParser вызовет метод делегата parser:didStartElement:namespaceURI:qualifiedName:attributes:.

Перед вызовом parser:didEndElement:namespaceURI:qualifiedName: для </my_next_element> метод делегата parser:foundCharacters: будет вызываться дважды со строками:

  1. "foo"
  2. "bar"

Ссылка на объект my_symbol игнорируется. Что требуется для разрешения ссылки на сущность?

РЕДАКТИРОВАТЬ:

Удаление ENTITY объявления my_symbol из DTD приведет к созданию NSXMLParserUndeclaredEntityError. Это говорит о том, что когда объявление объекта присутствует, а затем упоминается в <my_next_element>, оно замечается. По какой-то причине он просто не разрешается в строку, которую он представляет.

Кроме того, если внутри элемента используется &amp;, синтаксический анализатор правильно разрешит его в "&", и это будет передано в виде строки при вызове метода делегата parser:foundCharacters:.


person Ben Lever    schedule 09.10.2009    source источник
comment
можете ли вы найти его с помощью XPath?   -  person Kaiser Advisor    schedule 13.10.2009
comment
Я выполнил запрос XPath к 'my_element', и foo и bar также не были разрешены. Правильно ли ссылаться на внутренне объявленные сущности, как это сделал я?   -  person Ben Lever    schedule 14.10.2009
comment
честно говоря, не знаю, правильно это или нет, но уж точно нестандартно. Я не на 100% понимаю, почему вы просто не создадите 2 дочерних объекта, foo и bar. Тогда вы можете использовать XPath.   -  person Kaiser Advisor    schedule 14.10.2009
comment
Приведенный выше XML является примером, который я собрал для проверки своей проблемы. Если foo и bar являются отдельными дочерними объектами, XPath их найдет. Проблема в &my_symbol; не решается. XPath не может его найти.   -  person Ben Lever    schedule 15.10.2009
comment
Я сейчас натыкаюсь на эту проблему. Вы решили это?   -  person Nico Prananta    schedule 14.02.2014


Ответы (1)


Я просмотрел NSXMLParser.h, в котором перечислены следующие определенные методы для поддержки делегатов:

@interface NSObject (NSXMLParserDelegateEventAdditions)
// Document handling methods
- (void)parserDidStartDocument:(NSXMLParser *)parser;
    // sent when the parser begins parsing of the document.
- (void)parserDidEndDocument:(NSXMLParser *)parser;
    // sent when the parser has completed parsing. If this is encountered, the parse was successful.

// DTD handling methods for various declarations.
- (void)parser:(NSXMLParser *)parser foundNotationDeclarationWithName:(NSString *)name publicID:(NSString *)publicID systemID:(NSString *)systemID;

- (void)parser:(NSXMLParser *)parser foundUnparsedEntityDeclarationWithName:(NSString *)name publicID:(NSString *)publicID systemID:(NSString *)systemID notationName:(NSString *)notationName;

- (void)parser:(NSXMLParser *)parser foundAttributeDeclarationWithName:(NSString *)attributeName forElement:(NSString *)elementName type:(NSString *)type defaultValue:(NSString *)defaultValue;

- (void)parser:(NSXMLParser *)parser foundElementDeclarationWithName:(NSString *)elementName model:(NSString *)model;

- (void)parser:(NSXMLParser *)parser foundInternalEntityDeclarationWithName:(NSString *)name value:(NSString *)value;

- (void)parser:(NSXMLParser *)parser foundExternalEntityDeclarationWithName:(NSString *)name publicID:(NSString *)publicID systemID:(NSString *)systemID;

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
    // sent when the parser finds an element start tag.
    // In the case of the cvslog tag, the following is what the delegate receives:
    //   elementName == cvslog, namespaceURI == http://xml.apple.com/cvslog, qualifiedName == cvslog
    // In the case of the radar tag, the following is what's passed in:
    //    elementName == radar, namespaceURI == http://xml.apple.com/radar, qualifiedName == radar:radar
    // If namespace processing >isn't< on, the xmlns:radar="http://xml.apple.com/radar" is returned as an attribute pair, the elementName is 'radar:radar' and there is no qualifiedName.

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
    // sent when an end tag is encountered. The various parameters are supplied as above.

- (void)parser:(NSXMLParser *)parser didStartMappingPrefix:(NSString *)prefix toURI:(NSString *)namespaceURI;
    // sent when the parser first sees a namespace attribute.
    // In the case of the cvslog tag, before the didStartElement:, you'd get one of these with prefix == @"" and namespaceURI == @"http://xml.apple.com/cvslog" (i.e. the default namespace)
    // In the case of the radar:radar tag, before the didStartElement: you'd get one of these with prefix == @"radar" and namespaceURI == @"http://xml.apple.com/radar"

- (void)parser:(NSXMLParser *)parser didEndMappingPrefix:(NSString *)prefix;
    // sent when the namespace prefix in question goes out of scope.

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
    // This returns the string of the characters encountered thus far. You may not necessarily get the longest character run. The parser reserves the right to hand these to the delegate as potentially many calls in a row to -parser:foundCharacters:

- (void)parser:(NSXMLParser *)parser foundIgnorableWhitespace:(NSString *)whitespaceString;
    // The parser reports ignorable whitespace in the same way as characters it's found.

- (void)parser:(NSXMLParser *)parser foundProcessingInstructionWithTarget:(NSString *)target data:(NSString *)data;
    // The parser reports a processing instruction to you using this method. In the case above, target == @"xml-stylesheet" and data == @"type='text/css' href='cvslog.css'"

- (void)parser:(NSXMLParser *)parser foundComment:(NSString *)comment;
    // A comment (Text in a <!-- --> block) is reported to the delegate as a single string

- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock;
    // this reports a CDATA block to the delegate as an NSData.

- (NSData *)parser:(NSXMLParser *)parser resolveExternalEntityName:(NSString *)name systemID:(NSString *)systemID;
    // this gives the delegate an opportunity to resolve an external entity itself and reply with the resulting data.

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError;
    // ...and this reports a fatal error to the delegate. The parser will stop parsing.

- (void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError;
    // If validation is on, this will report a fatal validation error to the delegate. The parser will stop parsing.
@end

Судя по порядку записей в файле, ожидается, что найденные методы объявления появятся до того, как элементы будут найдены (как вы обнаружили). Я бы попробовал обработать все эти методы и посмотреть, встречаются ли какие-либо из них, но все они выглядят так, как будто они предназначены для других целей.

Интересно, есть ли способ инструментировать все необработанные сообщения, отправленные вашему делегату, на случай, если документация/интерфейс неполны.

person Epsilon Prime    schedule 15.10.2009
comment
Я реализовал всех делегатов в соответствии с вашим предложением и перезапустил. Тем не менее, делегат не вызывается, когда синтаксический анализатор достигает &my_symbol;. Как уже упоминалось, удаление объявления ENTITY вызовет метод resolveExternalEntityName, который предполагает, что он распознает его как ссылку на сущность. По какой-то причине, когда объявление ENTITY присутствует (и распознано), оно просто не разрешает ссылку на значение объекта. - person Ben Lever; 16.10.2009
comment
Следуя за моей надеждой, что это просто недокументированный вызов метода, я нашел эту страницу, на которой рассказывается о том, как создать прокси-объект. Предположительно, вы могли бы бросить это перед своим делегатом NSXMLParser и искать все, что не было обработано: borkware.com/rants/agentm/элегантная-делегация - person Epsilon Prime; 16.10.2009
comment
Но даже если окажется, что это недокументированное сообщение, которое вам нужно обработать, похоже, вам нужно будет сообщить об ошибке в Apple. Либо это должно быть задокументировано, либо это должно быть реализовано, а затем задокументировано. - person Epsilon Prime; 16.10.2009
comment
Я запустил nm и strings в /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk/System/Library/Frameworks/Foundation.framework/Foundation и не смог найти в делегате ничего, что отличалось бы от выше, и я не увидел каких-либо новых параметров (или настроек) синтаксического анализа, которые отличались бы от документации. Единственное, что я обнаружил, это то, что у подобных библиотек было два вызова, один для обработки сущностей, а другой для их пропуска. Я уверен, что вы уже пытались установить для всех значений setShould* значение YES, но безрезультатно. - person Epsilon Prime; 18.10.2009
comment
Я реализовал предложение использовать прокси-объект в качестве делегата, чтобы убедиться, что NSXMLParser не передает недокументированные сообщения. К сожалению, вызываются все ожидаемые методы делегата. Теперь я сообщу об этом как об ошибке в Apple и посмотрю, какой ответ я получу. - person Ben Lever; 21.10.2009