C++ 如何使用casablanca(PPL)http_客户端返回的XmlLite处理XML?
我希望向web服务发出请求,获取XML内容,并对其进行解析以获取服务返回的特定值 代码将用原生C++11(MS Visual Studio 2013)编写。选择了PPL库。对于XML解析,选择了XmlLite 我习惯C++编程;然而,来自PPL库的异步任务编程——这种方法——对我来说是新的。我知道什么是异步编程,我知道并行编程的原理。然而,我不习惯使用continuations(C++ 如何使用casablanca(PPL)http_客户端返回的XmlLite处理XML?,c++,c++11,asynchronous,ppl,xmllite,C++,C++11,Asynchronous,Ppl,Xmllite,我希望向web服务发出请求,获取XML内容,并对其进行解析以获取服务返回的特定值 代码将用原生C++11(MS Visual Studio 2013)编写。选择了PPL库。对于XML解析,选择了XmlLite 我习惯C++编程;然而,来自PPL库的异步任务编程——这种方法——对我来说是新的。我知道什么是异步编程,我知道并行编程的原理。然而,我不习惯使用continuations(.then(…)),我只是在慢慢地将我的脑袋绕到这个概念上 到目前为止,我已经修改了示例以获得XML结果并将其写入文本
.then(…)
),我只是在慢慢地将我的脑袋绕到这个概念上
到目前为止,我已经修改了示例以获得XML结果并将其写入文本文件:
// Open a stream to the file to write the HTTP response body into.
auto fileBuffer = std::make_shared<concurrency::streams::streambuf<uint8_t>>();
file_buffer<uint8_t>::open(L"test.xml", std::ios::out)
.then([=](concurrency::streams::streambuf<uint8_t> outFile) -> pplx::task < http_response >
{
*fileBuffer = outFile;
// Create an HTTP request.
// Encode the URI query since it could contain special characters like spaces.
// Create http_client to send the request.
http_client client(L"http://api4.mapy.cz/");
// Build request URI and start the request.
uri_builder builder(L"/geocode");
builder.append_query(L"query", address);
return client.request(methods::GET, builder.to_string());
})
// Write the response body into the file buffer.
.then([=](http_response response) -> pplx::task<size_t>
{
printf("Response status code %u returned.\n", response.status_code());
return response.body().read_to_end(*fileBuffer);
})
// Close the file buffer.
.then([=](size_t)
{
return fileBuffer->close();
})
// Wait for the entire response body to be written into the file.
.wait();
实际上,目标不是将流写入test.xml
文件以向XmlLite解析器提供数据。XML非常小,它包含一个或多个(如果地址不明确)具有我要提取的x和y属性的item元素,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<result>
<point query="Vítězství 27, Olomouc">
<item
x="17.334045"
y="49.619723"
id="9025034"
source="addr"
title="Vítězství 293/27, Olomouc, okres Olomouc, Česká republika"
/>
<item
x="17.333067"
y="49.61618"
id="9024797"
source="addr"
title="Vítězství 27/1, Olomouc, okres Olomouc, Česká republika"
/>
</point>
</result>
我不需要那个
test.xml
文件。如何获取流以及如何将其重定向到XmlLite解析器?我还没有使用卡萨布兰卡,因此这可能有点不合适。(我很想与卡萨布兰卡合作,但我必须先争取更多的时间。)也就是说,您显示的代码似乎将下载一个xml文件并将其保存到本地文件test.xml
。从这一点来看,如果xml文件是用UTF-8编码的,那么将该文件加载到XmlLite中就很简单了。如果它不是UTF-8,你将不得不跳转通过一些额外的环来解码它,无论是在内存中还是通过or,我在这里不做介绍
获得UTF-8文件或处理编码后,使用XmlLite启动XML解析的最简单方法如以下文档所示:
在您的情况下,您希望跳过该文件,因此需要在内存中创建一个IStream
。您有三个主要选择:
IStream
,然后在完成检索后将其用作源concurrency::streams::IStream
创建一个IStream
包装器,将其异步性隐藏在IStream
接口后面pFileStream
和pReader
的变量使用诸如ATL的CComPtr
和CComPtr
之类的RAII类,或我建议的pMemStream
。这也是您需要处理比XmlLite默认值更深的递归的时候。然后就是读取文件。方法中记录的最简单的循环;以下是一些最重要的部分,但请注意,为了可读性,我省略了错误检测:
void Summarize(IXmlReader *pReader, LPCWSTR wszType)
{
LPCWSTR wszNamespaceURI, wszPrefix, wszLocalName, wszValue;
UINT cchNamespaceURI, cchPrefix, cchLocalName, cchValue;
pReader->GetNamespaceURI(&wszNamespaceURI, &cchNamespaceURI);
pReader->GetPrefix(&wszPrefix, &cchPrefix);
pReader->GetLocalName(&wszLocalName, &cchLocalName);
pReader->GetValue(&wszValue, &cchValue);
std::wcout << wszType << L": ";
if (cchNamespaceURI) std::wcout << L"{" << wszNamespaceURI << L"} ";
if (cchPrefix) std::wcout << wszPrefix << L":";
std::wcout << wszLocalName << "='" << wszValue << "'\n";
}
void Parse(IXmlReader *pReader)
{
// Read through each node until the end
while (!pReader->IsEOF())
{
hr = pReader->Read(&nodeType);
if (hr != S_OK)
break;
switch (nodeType)
{
// : : :
case XmlNodeType_Element:
Summarize(pReader, L"BeginElement");
while (S_OK == pReader->MoveToNextAttribute())
Summarize(pReader, L"Attribute");
pReader->MoveToElement();
if (pReader->IsEmptyElement())
std::wcout << L"EndElement\n";
break;
case XmlNodeType_EndElement:
std::wcout << L"EndElement\n";
break;
// : : :
}
}
}
void摘要(IXmlReader*pReader,LPCWSTR wszType)
{
lpcwsstr wszNamespaceURI、wszPrefix、wszLocalName、wszValue;
UINT cchNamespaceURI、cchPrefix、cchLocalName、cchValue;
pReader->GetNamespaceURI(&wszNamespaceURI,&cchNamespaceURI);
pReader->GetPrefix(&wszPrefix,&cchPrefix);
pReader->GetLocalName(&wszLocalName,&cchLocalName);
预订单->获取值(&wszValue,&cchValue);
std::wcout谢谢,Michael。请看一下更新后的问题。更新部分之前的文本保持不变。@pepr执行我添加的关于SHCreateMemStream
/CreateStreamOnHGlobal
的部分,包括您要查找的内容吗?我现在专门阅读请求,以避免击中文件系统。记住编码在这里仍然是有意义的,因此在我使用XmlLitestd::string
(持有UTF-8)的经验中,它通常比std::wstring
更简单。坦率地说,我还没有尝试过。我明天会看一看。现在看一看,它似乎是响应。body()。read_to_end()
或类似的方法应该能够为XmlLite流提供信息。对于编码,提取的信息将是数字。此外,wxString
接受将char*
字符串解释为UTF-8编码字符串。我将询问细节,我接受答案。我明天将进行实验。无论如何,赏金是你的。
//Open read-only input stream
if (FAILED(hr = SHCreateStreamOnFile(argv[1], STGM_READ, &pFileStream)))
{
wprintf(L"Error creating file reader, error is %08.8lx", hr);
return -1;
}
if (FAILED(hr = CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, NULL)))
{
wprintf(L"Error creating xml reader, error is %08.8lx", hr);
return -1;
}
hr = pReader->SetInput(pStream);
void Summarize(IXmlReader *pReader, LPCWSTR wszType)
{
LPCWSTR wszNamespaceURI, wszPrefix, wszLocalName, wszValue;
UINT cchNamespaceURI, cchPrefix, cchLocalName, cchValue;
pReader->GetNamespaceURI(&wszNamespaceURI, &cchNamespaceURI);
pReader->GetPrefix(&wszPrefix, &cchPrefix);
pReader->GetLocalName(&wszLocalName, &cchLocalName);
pReader->GetValue(&wszValue, &cchValue);
std::wcout << wszType << L": ";
if (cchNamespaceURI) std::wcout << L"{" << wszNamespaceURI << L"} ";
if (cchPrefix) std::wcout << wszPrefix << L":";
std::wcout << wszLocalName << "='" << wszValue << "'\n";
}
void Parse(IXmlReader *pReader)
{
// Read through each node until the end
while (!pReader->IsEOF())
{
hr = pReader->Read(&nodeType);
if (hr != S_OK)
break;
switch (nodeType)
{
// : : :
case XmlNodeType_Element:
Summarize(pReader, L"BeginElement");
while (S_OK == pReader->MoveToNextAttribute())
Summarize(pReader, L"Attribute");
pReader->MoveToElement();
if (pReader->IsEmptyElement())
std::wcout << L"EndElement\n";
break;
case XmlNodeType_EndElement:
std::wcout << L"EndElement\n";
break;
// : : :
}
}
}