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

Reply via email to