Как я могу использовать POCO для анализа XML-файла и извлечения конкретного узла в std :: string?

Я хочу извлечь отдельный узел, используя библиотеки POCO, но не могу понять, как это сделать. Я новичок в XML.

Сам XML выглядит примерно так (сокращенно):

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created by XMLPrettyPrinter on 11/28/2012 from  -->
<sbml xmlns = "http://www.sbml.org/sbml/level2/version4" level = "2" version = "4">
<model id = "cell">
<listOfSpecies>
</listOfSpecies>
<listOfParameters>
<parameter id = "kk1" value = "1"/>
</listOfParameters>
<listOfReactions>
<reaction id = "J1" reversible = "false">
... much stuff here ..
</listOfReactions>
</model>
</sbml>

Я хочу извлечь все из узла listOfReactions и сохранить его в std :: string для последующего хеширования MD5.

Я попробовал это:

ifstream in(JoinPath(gTestDataFolder, "Test_1.xml").c_str());
InputSource src(in);
DOMParser parser;
AutoPtr<Document> pDoc = parser.parse(&src);
NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL);
Node* pNode = it.nextNode();

while(pNode)
{
clog<<pNode->nodeName()<<endl;
string elementID = "listOfReactions";
if(pNode->nodeName() == "listOfReactions")
{
//Extract everything in this node... how???
}

pNode = it.nextNode();
}

2

Решение

Я столкнулся с подобной проблемой сам. Например, в вашем случае с примененным фильтром «Poco :: XML :: NodeFilter :: SHOW_ALL» все типы узлов (Element, Text, CDataSection и т. Д.) Будут включены при итерации по документу XML. Я обнаружил, что POCO не включает в себя все данные в каждом узле, которые он возвращает из «NextNode ()».

Если кто-то хочет получить доступ к атрибутам узлов XML, сначала нужно запросить узел, чтобы проверить, есть ли у него какие-либо атрибуты, с помощью «hasAttributes ()», а затем, если это так, перебрать каждый из этих атрибутов, чтобы найти интересующие их.

Пример XML:

<?xml version="1.0"?>
<reaction id="J1" reversible="false">

Пример C ++:

...
Poco::XML::NamedNodeMap* attributes = NULL;
Poco::XML::Node* attribute = NULL;

while(pNode)
{
if( (pNode->nodeName() == "reaction") && pNode->hasAttributes())
{
attributes = pNode->attributes();
for(unsigned int i = 0; i < attributes->length(); i++)
{
attribute = attributes->item(i);
cout << attribute->nodeName() << " : " << attribute->nodeValue() << endl
}
}
pNode = it.nextNode();
}
...

Должен выводить:

id : J1
reversible : false

Если кто-то хочет получить доступ к тексту между двумя тегами XML, как показано в примере XML ниже, сначала нужно найти узел с именем, совпадающим с интересующим тегом, как вы это сделали в своем примере, а затем проверить следующее узел, вызывая «NextNode ()», чтобы увидеть, имеет ли этот узел имя узла «#text» или «# cdata-section». Если это так, значение этого «следующего узла» будет содержать текст между тегами XML.

Пример XML:

<?xml version="1.0"?>
<listOfReactions>Some text</listOfReactions>

Пример C ++:

...
while(pNode)
{
if(pNode->nodeName() == "listOfReactions")
{
pNode = it.nextNode();
if(pNode->nodeName() != "#text")
{
continue; //No text node present
}
cout << "Tag Text: " << pNode->nodeValue() << endl;
}
pNode = it.nextNode();
}
...

Должен выводить:

Some text
4

Другие решения

Пытаться эти слайды, и Документация Poco для справки API.

Также есть хороший учебник здесь который имеет простой для понимания пример того, что вы пытаетесь сделать.

0

Поздно к игре, но, возможно, все еще полезно. Я изучаю Poco XML для извлечения данных о погоде, представленных в формате XML. Я нашел PDF-слайд @JBently упоминание как хорошее введение. Это обеспечивает hpp-файл. это пример охватывает реализацию. Я опустил LexicalHandler.

Я присматриваю за строкой listOfReactions, и, когда она найдена, я добавляю имя-атрибута и -value к строке в startElement (). В символах () я добавляю текст в узле в строку и добавляю его в вектор, который можно обойти.

Выход:

id = J1, обратимый = ложный, ложный ход
id = J2, обратимый = верный, верный ход

Я немного изменил ваш xml для тестирования и избежал двойных кавычек для использования в программе.

<?xml version=\"1.0\" encoding=\"UTF-8\"?><sbml xmlns = \"http://www.sbml.org/sbml/level2/version4\" level = \"2\" version = \"4\">
<model id = \"cell\">
<listOfSpecies>species</listOfSpecies>
<listOfParameters>
<parameter id = \"kk1\" value = \"1\"/>
</listOfParameters>
<listOfReactions>
<reaction id = \"J1\" reversible = \"false\">false move</reaction>
<reaction id = \"J2\" reversible = \"true\">true move</reaction>
</listOfReactions>
</model>
</sbml>

главный:

#include <iostream>

#include "MyHandler.hpp"
using namespace std;

int main() {
auto s = {XML file from above};
MyHandler handler {};
Poco::XML::SAXParser parser {};
parser.setFeature(Poco::XML::XMLReader::FEATURE_NAMESPACES, false);
parser.setFeature(Poco::XML::XMLReader::FEATURE_NAMESPACE_PREFIXES, true);
parser.setContentHandler(&handler);

try {
parser.parseString(s);
} catch (Poco::Exception& e) {
cerr << e.displayText() << endl;
}
auto saved = handler.saved_reactions();
for (auto& i : saved) {
cout << i << endl;
}
return 0;
}

MyHandler.hpp:

#ifndef MYHANDLER_HPP_
#define MYHANDLER_HPP_

#include <iostream>
#include <vector>
#include <Poco/SAX/Attributes.h>
#include <Poco/SAX/ContentHandler.h>
#include <Poco/SAX/SAXParser.h>

class MyHandler: public Poco::XML::ContentHandler {
public:
MyHandler();
virtual ~MyHandler();

// ContentHandler overrides, begin.
void setDocumentLocator(const Poco::XML::Locator* loc);
void startDocument();
void endDocument();
void startElement(
const Poco::XML::XMLString&,
const Poco::XML::XMLString&,
const Poco::XML::XMLString&,
const Poco::XML::Attributes&);
void endElement(
const Poco::XML::XMLString&,
const Poco::XML::XMLString&,
const Poco::XML::XMLString&);
void characters(const Poco::XML::XMLChar ch[], int, int);
void ignorableWhitespace(const Poco::XML::XMLChar ch[], int, int);
void processingInstruction(const Poco::XML::XMLString&, const Poco::XML::XMLString&);
void startPrefixMapping(const Poco::XML::XMLString&, const Poco::XML::XMLString&);
void endPrefixMapping(const Poco::XML::XMLString&);
void skippedEntity(const Poco::XML::XMLString&);
// ContentHandler overrides, end
std::vector<std::string> saved_reactions();

private:
bool show = false;
std::string reactions_s {};
std::vector<std::string> reactions_v {};
};

#endif /* MYHANDLER_HPP_ */

MyHandler.cpp:

#include "MyHandler.hpp"
MyHandler::MyHandler() {}
MyHandler::~MyHandler() {}

void MyHandler::setDocumentLocator(const Poco::XML::Locator* loc) {
}

void MyHandler::startDocument() {
}

void MyHandler::endDocument() {
}

void MyHandler::startElement(const Poco::XML::XMLString& namespaceURI, const Poco::XML::XMLString& localName, const Poco::XML::XMLString& qname, const Poco::XML::Attributes& attributes) {
int x {0};
std::cout << "qname: " << qname << std::endl;
/*    std::cout << "getValue(): " << attributes.getValue(qname) << std::endl;
std::cout << "getLength(): " << attributes.getLength() << std::endl;*/
if (qname == "listOfReactions") {
show = true;
}
if (show) {
if (attributes.getLength()) {
reactions_s.clear();
x = attributes.getLength();
for (int i = 0; i < x; ++i) {
std::cout << "getQName(): " << attributes.getQName(i) << ", getValue(): " << attributes.getValue(i) << std::endl;
if (reactions_s.size()) reactions_s += ",";
reactions_s += attributes.getQName(i) + "=" + attributes.getValue(i);
}
}
}
}

void MyHandler::endElement(const Poco::XML::XMLString& allocator,
const Poco::XML::XMLString& allocator1,
const Poco::XML::XMLString& allocator2) {
}

void MyHandler::characters(const Poco::XML::XMLChar ch[], int start, int length) {
std::cout << std::string(ch + start, length) << std::endl;
if (show) {
reactions_s += "," + std::string(ch + start, length);
reactions_v.emplace_back(reactions_s);
}
}

void MyHandler::ignorableWhitespace(const Poco::XML::XMLChar ch[], int start, int length) {
}

void MyHandler::processingInstruction(const Poco::XML::XMLString& allocator, const Poco::XML::XMLString& allocator1) {
}

void MyHandler::startPrefixMapping(const Poco::XML::XMLString& allocator, const Poco::XML::XMLString& allocator1) {
}

void MyHandler::endPrefixMapping(const Poco::XML::XMLString& allocator) {
}

std::vector<std::string> MyHandler::saved_reactions() {
return reactions_v;
}

void MyHandler::skippedEntity(const Poco::XML::XMLString& allocator) {
}
0

Предполагая XML ниже в файле «hello.xml»

<root>
<headers>
<header>Hello</header>
<header>World</header>
</headers>
</root>

Можно разобрать это так:

#include <string>
#include <sstream>
#include <Poco/Exception.h>
#include <Poco/AutoPtr.h>
#include <Poco/Util/XMLConfiguration.h>

using namespace std;
using namespace Poco;
using namespace Poco::Util;

int main(int argc, char*argv[]) {

int counter = 0;
AutoPtr apXmlConf(new XMLConfiuration("hello.xml"));
try {
while(1) { // Loop breaks by Poco exception
stringstream tag;
tag << "headers.header[" << counter++ << "]";
string header = apXmlConf->getString(tag.str());
cout << header << " ";
}
} catch(NotFoundException& e) { (void)e; }
cout << endl;
return 0;
}

Надеюсь, это поможет.

-1
По вопросам рекламы [email protected]