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