libxml2 - xmlNodeSetContent 和实体麻烦
我正在为 iOS 创建一个应用程序,它使用 libxml2 生成一些 XML,稍后将其用作 SOAP 请求。我编写了一个递归函数,它采用 NSDictionary 作为参数,并根据其嵌套结构生成 XML 节点(我允许将 NSDictionary 设置为另一个 NSDictionary 中的值)。我遇到了这样的情况:这还不够,我想手动创建一些 XML,然后将其放入某个节点内。我发现使用我当前的代码是不可能的。
libxml2 自动替换所有特殊字符,包括明显重要的 <
和 >
及其 HTML 实体对应项 - 例如 <
和 >
。尽管我在网上读到我需要手动编码它们 - 使用 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;
}
有什么方法可以实现这一点吗?
I'm making an application for iOS which uses libxml2 to generate some XML which is later used as a SOAP request. I wrote a recursive function which takes a NSDictionary as a parameter and generates XML nodes according to its nested structure (I allow a NSDictionary to be set as a value in another NSDictionary). I ran into a situation where it is not enough and I want to manually create some XML and then put it inside of a certain node. I found out that it is not possible using my current code.
libxml2 automatically substitutes all special characters, including <
and >
that are obviously essential, with their HTML entity correspondents - like <
and >
. Even though I've read on the web that I need to encode them manually - using xmlEncodeEntitiesReentrant. I'm pretty clueless. All I need to do is to temporarily disable that substitution in order to put some clean XML code into a node.
Here's a snippet from my application's source:
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;
}
Is there any way to accomplish that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我以一种不优雅的方式解决了它。我定义了自己的实体 - 例如
<
字符的!#LT#!
。然后,我只需将使用此类字符集的字符串放入 XML 树中,并在 libxml 完成生成 XML 请求后立即将所有出现的这些字符集替换为其适当的对应项。到目前为止似乎完成了这项工作,但您必须记住检查所有用户输入字段中的自定义实体,以确保用户不会搞砸您的整个请求。I solved it in a not elegant way. I defined my own entities - like
!#LT#!
for the<
character. Then I simply put strings that are using such sets of characters into the XML tree and replace all occurrences of those sets with their adequate correspondents right after libxml finishes generating the XML request. Seems to do the job so far but you have to remember to check for the self-defined entities in all your user input fields in order to make sure that the user does not screw up your whole request.