libxml2 - xmlNodeSetContent и проблемы с сущностями - PullRequest
1 голос
/ 29 июля 2011

Я делаю приложение для iOS, которое использует libxml2 для генерации некоторого XML, который позже используется как запрос SOAP. Я написал рекурсивную функцию, которая принимает NSDictionary в качестве параметра и генерирует узлы XML в соответствии с его вложенной структурой (я позволяю NSDictionary быть установленным в качестве значения в другом NSDictionary). Я столкнулся с ситуацией, когда этого недостаточно, и я хочу вручную создать XML-файл, а затем поместить его в определенный узел. Я обнаружил, что это невозможно с использованием моего текущего кода.

libxml2 автоматически заменяет все специальные символы, в том числе < и >, которые, очевидно, необходимы, их соответствующими сущностями HTML - такими как &lt; и &gt;. Несмотря на то, что я прочитал в Интернете, что мне нужно кодировать их вручную - используя xmlEncodeEntitiesReentrant. Я довольно невежественен. Все, что мне нужно сделать, это временно отключить эту замену, чтобы поместить в узел какой-то чистый XML-код.

Вот фрагмент из источника моего приложения:

void generate_xml(xmlNodePtr root, NSDictionary *dict) {
    for (NSString *key in dict) {
        xmlNodePtr node = NULL;
        id obj = [dict valueForKey:key];

        if ([obj isKindOfClass:[NSDictionary class]]) {
            node = xmlNewNode(NULL, BAD_CAST [key UTF8String]);
            xmlAddChild(root, node);
            generate_xml(node, obj);
        } else if ([key isEqual:@"text"]) {
            xmlNodeSetContent(root, BAD_CAST [obj UTF8String]);
    } else if ([key isEqual:@"text_with_tags"]) {
        //disable encoding the special characters and go on
            xmlNodeSetContent(root, BAD_CAST [obj UTF8String]);
        } else {
            xmlNewProp(root, BAD_CAST [key UTF8String], BAD_CAST [obj UTF8String]);
        }
    }
}

- (NSData *)prepareRequestBody {
    NSData *data = nil;
    xmlDocPtr doc = NULL;
    xmlNodePtr root = NULL;
    xmlNodePtr node = NULL;
    xmlNodePtr body = NULL;
    char *buffer = NULL;
    int length = 0;

    doc = xmlNewDoc(BAD_CAST "1.0");
    root = xmlNewNode(NULL, BAD_CAST "SOAP-ENV:Envelope");
    xmlNewProp(root, BAD_CAST "xmlns:xsd", BAD_CAST "http://www.w3.org/2001/XMLSchema");
    xmlNewProp(root, BAD_CAST "xmlns:xsi", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
    xmlNewProp(root, BAD_CAST "xmlns:SOAP-ENC", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/");
    xmlNewProp(root, BAD_CAST "SOAP-ENV:encodingStyle", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/");
    xmlNewProp(root, BAD_CAST "xmlns:SOAP-ENV", BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/");
    xmlDocSetRootElement(doc, root);
    body = xmlNewChild(root, NULL, BAD_CAST "SOAP-ENV:Body", NULL);
    node = xmlNewChild(body, NULL, BAD_CAST [[NSString stringWithFormat:@"m:%@", method] UTF8String], NULL);
    xmlNewProp(node, BAD_CAST "xmlns:m", BAD_CAST [[url absoluteString] UTF8String]);

    generate_xml(node, arguments);

    xmlDocDumpMemoryEnc(doc, (xmlChar **)&buffer, &length, "UTF-8");
    data = [NSData dataWithBytes:buffer length:length];
    xmlFree(buffer);
    xmlFreeDoc(doc);

    return data;
}

Есть ли способ сделать это?

1 Ответ

0 голосов
/ 29 июля 2011

Я решил это не элегантным способом.Я определил свои собственные сущности - например, !#LT#! для символа <.Затем я просто помещаю строки, использующие такие наборы символов, в дерево XML и заменяю все вхождения этих наборов их соответствующими корреспондентами сразу после того, как libxml завершит генерацию запроса XML.Кажется, что до сих пор выполняет эту работу, но вы должны помнить, чтобы проверить наличие самоопределенных сущностей во всех ваших полях ввода пользователя, чтобы убедиться, что пользователь не испортил весь ваш запрос.

...