Сбор вывода предупреждения 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: незарегистрированная среда выполнения функции

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

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

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

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

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

Большое спасибо!


person ABach    schedule 17.04.2013    source источник


Ответы (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. Это было бы намного безопаснее, но и сложнее (если это вообще возможно).

person Simon M    schedule 22.04.2013
comment
Фантастика, @SimonM - спасибо за это копание. Я поиграю и посмотрю, что у меня получится. - person ABach; 22.04.2013