2009-10-09 10 views
6

Tengo un archivo XML que usa entidades declaradas internamente. Por ejemplo:Cómo resolver una referencia de entidad XML declarada internamente utilizando NSXMLParser

<?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> 

... 

Utilización de la clase NSXMLParser, cómo soy capaz de resolver la referencia my_symbol entidad?

De la experimentación, se llamará al método de delegado parser:foundInternalEntityDeclarationWithName:value: para la declaración de entidad my_symbol, con el valor "my symbol value". Luego, cuando se alcanza el elemento my_next_element, NSXMLParser llamará al método delegado parser:didStartElement:namespaceURI:qualifiedName:attributes:.

Antes parser:didEndElement:namespaceURI:qualifiedName: se llama para </my_next_element>, el método parser:foundCharacters: delegado se llamará dos veces con las cadenas: se ignora

  1. "foo"
  2. "bar"

La referencia my_symbol entidad. ¿Qué se requiere para que se resuelva la referencia de la entidad?

EDIT:

Extracción de la declaración de ENTITYmy_symbol de la DTD se traducirá en un NSXMLParserUndeclaredEntityError. Esto sugiere que cuando la declaración de la entidad está presente, y luego se hace referencia en <my_next_element>, se está notando. Por alguna razón, no se está resolviendo con la cadena que representa.

Además, si &amp; se utiliza dentro de un elemento, el analizador resolverá correctamente a "&" y esto se pasa como la cuerda cuando se llama al método parser:foundCharacters: delegado.

+0

Estoy topando con este problema ahora. ¿Lo resolviste? –

+0

¿Puedes encontrarlo con [XPath] (http://en.wikipedia.org/wiki/XPath)? –

+0

Realicé una consulta XPath en 'my_element' y tampoco se resolvieron tanto "foo" como "bar". ¿Es correcto hacer referencia a las entidades declaradas internamente como lo hice? –

Respuesta

2

I revisado NSXMLParser.h que enumera los siguientes métodos definidos para que los delegados apoyan:

@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 

Basado en el orden de las entradas en el archivo se ve Se espera que los métodos de declaración observado que se producen antes de que los elementos están encontrado (como has descubierto). Intentaría manejar todos estos métodos y ver si ocurre alguno de ellos, pero todos parecen diseñados para otros usos.

Me pregunto si hay una forma de instrumentar todos los mensajes no enviados enviados a su delegado en caso de que la documentación/interfaz esté incompleta.

+0

Implementé todos los delegados, según su sugerencia, y volví a ejecutar. Aún así, no se llama a ningún delegado cuando el analizador llega a "& my_symbol;".Como se mencionó, la eliminación de la declaración ENTITY llamará al método "resolveExternalEntityName" que sugiere que lo está reconociendo como una referencia de entidad. Por alguna razón, cuando la declaración ENTIDAD está presente (y es reconocida), simplemente no está resolviendo la referencia al valor de la entidad. –

+1

Siguiendo con mi esperanza de que sea solo una llamada a un método no documentado, encontré esta página que habla sobre cómo crear un objeto proxy. Presumiblemente, podría lanzar esto delante de su delegado NSXMLParser y buscar cualquier cosa que no se haya manejado: http://borkware.com/rants/agentm/elegant-delegation/ –

+0

Pero incluso si resulta ser un mensaje no documentado debes manejarlo, parece que tendrás que informar un error a Apple. O necesita ser documentado o necesita ser implementado y luego documentado. –

Cuestiones relacionadas