John P. Wilson wrote:
I have the following type of XML:
...
I want to be able to get a list of the “ns1:pinchpoint” nodes, and then
step through each node in the list and extract the boundingCylinder1,
boundingCylinder2, location, and flow/resistance or flow/closure data.
I have been able to get the list of pinchpoint nodes, and then I can
extract **one** of the desired sub-nodes (such as boundingCylinder1),
but I can not then extract the other child nodes. Here is my code:
XMLPlatformUtils::Initialize();
XPathEvaluator::initialize();
XercesDOMParser *parser = new XercesDOMParser;
parser->setDoNamespaces(true);
parser->setDoSchema(true);
parser->setValidationSchemaFullChecking(true);
parser->setCreateEntityReferenceNodes(true);
DOMDocument *doc = 0;
parser->parse(argv[1]);
doc = parser->getDocument();
// The XPath expression to evaluate
std::string xpath = "/ns1:IPEModelInput/ns1:system/ns1:pinchpoint";
...
NodeRefList nodelist;
evaluator.selectNodeList(
nodelist,
dom_support,
root_context_node,
expression.c_str(),
namespace_node);
NodeRefList::size_type length = nodelist.getLength();
cout << "number of nodes = " << length << endl;
for (unsigned int i = 0; i < nodelist.getLength(); ++i) {
// Get this pinchpoint node
char newxpath[1024];
sprintf(newxpath,"%s[%d]",xpath.c_str(),i+1);
I don't know you've decided execute another XPath expression here. You
seem to want to select each node in the nodeset individually, but that's
not what you're doing. You need to understand the semantics of positional
predicates, but that's beyond the scope of this list.
Since you've already selected all of the ns1:pinchpoint children,
all you need to do is to iterate them, and your loop is doing just that.
XalanDOMString newexpression(newxpath);
cout << "pinchpoint path = " << newxpath << endl;
XalanNode* node = nodelist.item(i);
XalanNode* const theContextNode =
evaluator.selectSingleNode(
dom_support,
node,
newexpression.c_str(),
namespace_node);
Instead of evaluating this XPath expression, you can simply use "node" as
the context node for the following expressions.
// Get the location - THIS WORKS
XalanDOMString locationDOMStr("ns1:location");
const XObjectPtr locationResult(
evaluator.evaluate(
dom_support,
theContextNode,
locationDOMStr.c_str(),
namespace_node));
assert(locationResult.null() == false);
cout << "The location = "
<< locationResult->str()
<< endl;
// Get the first bounding cylinder - THIS DOESN’T WORK
XalanDOMString boundaryDOMStr("ns1:boundingCylinder1");
const XObjectPtr boundaryResult(
evaluator.evaluate(
dom_support,
theContextNode,
boundaryDOMStr.c_str(),
namespace_node));
assert(boundaryResult.null() == false);
cout << "Boundary 1 = "
<< boundaryResult->str()
<< endl;
}
The “assert” before I print boundaryResult is always thrown.
No, it's different assert. You've not read the documentation for the
function you're calling, and as a result, you're violating one of its
preconditions. Here is the excerpt from the header file:
/**
* Evaluate the supplied XPath expression, within the given context. The
* result is returned as a generalized object. The object will be
* destroyed when the user's copy of the returned XObjectPtr goes out of
* scope, or when the XPathEvaluator goes out of scope or another expression
* is evaluated.
*
* The user's XObjectPtr copy _must_ no longer be in scope when the
XPathEvaluator
* instance goes out of scope, or another expression is evaluated.
Note that you must ensure the XObjectPtr instance is destroyed before you
call evaluate() again.
How do I step through each “pinchpoint” object and extract the data?
Use extra scope to insure that all of your previous result objects have
been destroyed, or use selectNodeList, instead of evaluate(), just as you
did when you selected the ns1:pinchpoint elements. As a quick fix for your
code, I did the following:
{
const XObjectPtr locationResult(
evaluator.evaluate(
dom_support,
node,
locationDOMStr.c_str(),
namespace_node));
assert(locationResult.null() == false);
cout << "The location = "
<< locationResult->str()
<< endl;
}
// Get the first bounding cylinder - THIS DOESN’T WORK
XalanDOMString boundaryDOMStr("ns1:boundingCylinder1");
{
const XObjectPtr boundaryResult(
evaluator.evaluate(
dom_support,
node,
boundaryDOMStr.c_str(),
namespace_node));
assert(boundaryResult.null() == false);
cout << "Boundary 1 = "
<< boundaryResult->str()
<< endl;
}
Dave