LubinLew Ответов: 1

[Libxml2 xpath] как запросить атрибут со строкой, содержащей одинарные кавычки и двойные кавычки одновременно


В Примере xml атрибут lang содержит одинарные кавычки и двойные кавычки одновременно
<?xml version="1.0" encoding="UTF-8"?>
<test>
	<node lang="'"word" />
</test>


Что я уже пробовал:

Я пишу программу на языке Си, но она подсказывает мне, что
Ошибка XPath : недопустимый предикат
//node[@lang=""word']


/*
gcc -g `xml2-config --cflags` test.c `xml2-config --libs`
*/

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>

#define XML_FILE_PATH "test.xml"

int main(void)
{
	xmlDocPtr doc = NULL;
	xmlXPathObjectPtr object = NULL;
	xmlXPathContextPtr context = NULL;
	xmlNodePtr curr = NULL;
	xmlNodeSetPtr pNodeSet = NULL;
	xmlChar* prop = NULL;
	char lang[] = "'\"word";
	char xpath[256];

	doc = xmlParseFile(XML_FILE_PATH);
	if (NULL == doc) {
		printf("xmlParseFile failed");
		return -1;
	}
	context = xmlXPathNewContext(doc);
	if (NULL == context) {
		printf("xmlXPathNewContext failed");
		return -1;
	}
	
	/* Create Object */
	snprintf(xpath, sizeof(xpath), "//node[@lang='%s']", lang);
	object = xmlXPathEvalExpression((xmlChar*)xpath, context);
	xmlXPathFreeContext(context);
	if (object == NULL) {
		printf("xmlXPathEvalExpression (%s) failed", xpath);
		return -1;
	}
	
	/* NodeSet Is Empty ? */
	if(xmlXPathNodeSetIsEmpty(object->nodesetval)) {
		xmlXPathFreeObject(object);
		printf("xmlXPathNodeSetIsEmpty");
		return 0;
	}

	pNodeSet = object->nodesetval;
	curr = pNodeSet->nodeTab[0];

	prop = xmlGetProp(curr, (xmlChar *)"lang");
	printf("xmlGetProp %s", prop);
	xmlFree(prop);
	xmlXPathFreeObject(object);
	xmlFreeDoc(doc);

	return 0;
}

Maciej Los

Похоже, что xml не очень хорошо сформирован...

1 Ответов

Рейтинг:
1

Jochen Arndt

Вы должны использовать ссылки на символы или сущности (Список ссылок на сущности символов XML и HTML - Википедия[^]).

В вашем случае это было бы так:

char lang[] = "&apos;&quot;word";

Вы также можете написать функцию для этого:
// Or use boost::replace_all
void replace_all(std::string& str, const std::string& search, const std::string& replace)
{
    size_t len = search.length();
    size_t pos = str.find(search);
    while (std::string::npos != npos)
    {
        str.replace(pos, len, replace);
        pos = str.find(search, pos + len);
    }
}

void Xmlify(std::string& str)
{
    replace_all(str, "&", "&amp;"); // Must be the first
    replace_all(str, "<", "&lt;");
    replace_all(str, ">", "&gt;");
    replace_all(str, "\"", "&quot;");
    replace_all(str, "'", "&apos;");
}