como extrair dados de cacau iPhone sax rotina xml parsing
-
09-09-2019 - |
Pergunta
Eu estou tentando ler e analisar um documento XML em um aplicativo para iPhone. Eu começar a analisar e, em seguida, usar o método de substituição:
static void startElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
Eu, então, tentar converter os atributos para uma string com:
NSString *str1 = [[NSString alloc] initWithCString:attributes encoding:NSUTF8StringEncoding];
Por que os atributos parâmetro tem duas ** na frente dele. E por que quando se tenta extrair os dados e convertê-lo para uma string com o código acima que eu recebo o aviso:
passando argumento de um 'initWithCString: que codifica:'. Do tipo de ponteiro incompatível
Solução
A documentação para o elemento de retorno de chamada estados da libxml início que o ponteiro é uma matriz que mantenha 5 valores para cada atributo (o número de atributos é retornado em nb_attributes). Isto significa que cada 5ª valor na matriz é um novo item de atributo.
Os cinco itens para cada atributo são:
- localname (o nome do atributo)
- prefixo (o namespace do atributo)
- URI
- [início de] valor (um ponteiro para o início da corda xmlChar para o valor)
- fim [de valor] (um ponteiro para o final do corda xmlChar para o valor)
Então, você precisa passo através do array, obter cada valor fora dos itens para o primeiro atributo, em seguida, utilize o ponteiro do valor inicial para obter a seqüência xmlChar que é o comprimento = fim - início. Em seguida, começar de novo com o próximo atributo até que você leia em valor nb_attributes.
Se isso faz com que sua dor de cabeça, então eu sugiro fortemente que você alternar para o da Apple NSXMLParser (ligação pode exigir login, ou use este link NSXMLParser ). No caso que você deseja obter os atributos como um NSDictionary. Para obter todos os atributos de fora você poderia fazer o seguinte:
for (NSString *attributeName in [attributeDict allKeys]) {
NSString *attributeValue = [attributeDict objectForKey:attributeName];
// do something here with attributeName and attributeValue
}
Se você tem acesso ao site de desenvolvedores do iPhone, em seguida, olhar para o exemplo SeismicXML .
Outras dicas
A amostra é grande, exceto por duas coisas:
- você precisa bater 'i' por 5 após cada ciclo uma vez que existem 5 itens para cada atributo.
- Fazer strlen () em ambos começam e terminam é caro; é mais fácil basta subtrair começar a partir do final
for (int i = 0; i < nb_attributes*5; i += 5)
{
const char *attr = (const char *)attributes[i];
const char *begin = (const char *)attributes[i + 3];
const char *end = (const char *)attributes[i + 4];
int vlen = end - begin;
char val[vlen + 1];
strncpy(val, begin, vlen);
val[vlen] = '\0';
NSLog(@"attribute %s = '%s'", attr, val);
}
O respostas explicação aceita é correta, mas é útil para ver um exemplo de código também. Aqui é apenas uma maneira de extrair o valor dos atributos, pelo menos ele funciona quando eu testei. Estou longe de ser um guru C embora.
for (int i = 0; i < nb_attributes; i += 5) {
const char *attr = (const char *)attributes[i];
const char *begin = (const char *)attributes[i + 3];
const char *end = (const char *)attributes[i + 4];
int vlen = strlen(begin) - strlen(end);
char val[vlen + 1];
strncpy(val, begin, vlen);
val[vlen] = '\0';
NSLog(@"attribute %s: %d = %s", attr, i, val);
}
NSXMLParser é agradável, mas pelo que eu posso dizer, ele faz o download de todo o XML antes do processamento. Usando libxml ele pode ler em pedaços de cada vez. Ele permite maior flexibilidade, mas maior curva de aprendizagem.
Os meios de notação '**'
"ponteiro para um ponteiro." Em C / C ++, uma "cadeia" é representado por um conjunto de caracteres. Uma matriz é realmente apenas um ponteiro sob o cobre, por isso, uma cadeia em C / C ++ pode realmente ser declarado como seja "char []" ou "char *". O [] notação compila para baixo para um apontador para uma matriz.
Um exemplo comum é a função normal "principal" em C / C ++:
int main(int argc, char **argv)
O que é equivalente a:
int main(int argc, char *argv[])
argv é uma matriz de char * "strings" (os argumentos de linha de comando para o programa).
Eu não posso dar um exemplo, no momento, mas parece que você precisa iterar sobre atributos para acessar as cordas individuais. Por exemplo, os atributos [0] seria a primeira cadeia de atributo (um xmlChar *). Você deve ser capaz de converter cada atributo individual para um NSString.
const xmlChar **namespaces
é uma matriz de CStrings (int nb_namespaces
informa quantas). Se você deseja que cada namespace como um NSString, você poderia fazer algo como o seguinte:
NSMutableArray *namespaces = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < nb_namespaces; i++) {
NSString *namespace = [[NSString alloc] initWithCString:attributes[i] encoding:NSUTF8StringEncoding];
[namespaces addObject:namespace];
}
O método initWithCString
espera xmlChar *
, que é um
meios xmlChar **