Сбор вывода предупреждения NSXMLDocument

У меня есть следующая вспомогательная функция для преобразования XML через XSLT:

- (NSXMLDocument *)transform:(NSString *)xml :(NSString *)xslt
{
    NSError *xmlDocErr = nil;
    NSXMLDocument *transformedXmlDoc = nil;

    NSXMLDocument *xmlDoc = [[NSXMLDocument alloc]
                              initWithXMLString:xml
                              options:NSXMLDocumentValidate
                              error:&xmlDocErr];

    if (xmlDocErr) {
        NSLog(@"Error: %@", [xmlDocErr localizedDescription]);
    }
    else {
        transformedXmlDoc = [xmlDoc objectByApplyingXSLTString:xslt 
                                    arguments:nil
                                    error:&xmlDocErr];
        if (xmlDocErr) {
            NSLog(@"Error: %@", [xmlDocErr localizedDescription]);
        }
    }

    return transformedXmlDoc;
}

Это работает, как и ожидалось, но есть небольшая странность, с которой я мог бы помочь.

Когда я пытаюсь использовать функцию XSLT, которая неизвестна NSXMLDocument (скажем, EXSLT node-set()), Я получаю вывод в Xcode, аналогичный приведенному ниже - первая строка, в частности, представляет интерес:

xmlXPathCompOpEval: набор узлов функции не найден

Ошибка XPath: время работы незарегистрированной функции

ошибка: элемент для каждого

Не удалось оценить выражение "select".

Это круто; это именно то, что я ожидал.

Однако мне интересно, что вывод не содержит "Error: " в любом месте (что должно быть в случае, если этот вывод был захвачен моим [xmlDocErr localizedDescription] звонки).

Итак, вот вопрос: как я могу получить вышеуказанный вывод (чтобы я мог использовать его для отображения соответствующих сообщений для моего пользователя)?

Спасибо!

1 ответ

Решение

Ошибка происходит глубоко внутри libxml по линии 13479 из xpath.c, который заканчивает тем, что звонил xmlGenericErrorDefaultFunc() на линии 71 error.c, который печатает на stderr, Так что самый простой способ сделать это, чтобы захватить stderr пока идет обработка XSLT:

- (NSXMLDocument *)transform:(NSString *)xml :(NSString *)xslt
{
    NSError *xmlDocErr = nil;
    NSXMLDocument *transformedXmlDoc = nil;

    NSXMLDocument *xmlDoc = [[NSXMLDocument alloc]
                             initWithXMLString:xml
                             options:NSXMLDocumentValidate
                             error:&xmlDocErr];

    if (xmlDocErr) {
        NSLog(@"Error: %@", [xmlDocErr localizedDescription]);
    }
    else {
        // Pipe for stderr
        NSPipe *pipe = [NSPipe pipe];
        // Duplicate of stderr (will use later)
        int cntl = fcntl(STDERR_FILENO,F_DUPFD);
        // Redirect stderr through our pipe
        dup2([[pipe fileHandleForWriting] fileDescriptor], STDERR_FILENO);

        transformedXmlDoc = [xmlDoc objectByApplyingXSLTString:xslt
                                                     arguments:nil
                                                         error:&xmlDocErr];
        // Get the data
        NSData *dat = [[pipe fileHandleForReading] availableData];
        // Redirect stderr through our duplicate, to restore default output behavior
        dup2(cntl, STDERR_FILENO);
        // Did anything get logged?
        if ([dat length]>0) {
            NSLog(@"Error: %@", [[NSString alloc] initWithData:dat encoding:NSASCIIStringEncoding]);
        }
        if (xmlDocErr) {
            NSLog(@"Error: %@", [xmlDocErr localizedDescription]);
        }
    }

    return transformedXmlDoc;
}

Но это немного взломать, так что будьте осторожны...

Если вы не удовлетворены этим решением, должна быть возможность переопределить переменную xmlGenericError (который, по умолчанию, ссылки xmlGenericErrorDefaultFunc) с пользовательской функцией обработки ошибок по вашему усмотрению initGenericErrorDefaultFunc по строке 864 из xmlerror.h, Это было бы намного безопаснее, но и сложнее (если это вообще возможно).

Другие вопросы по тегам