You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-users@xalan.apache.org by King Nak <ki...@gmx.net> on 2006/08/17 09:24:04 UTC

Evaluating XPath on NodeSet

Hi!

I'm a novice to xalan and have a problem:
I've got a big XML file representing a product calalogue. here an example
excerpt:
<catalogue>
  <chapter>
    <!-- some more hierarchy -->
    <product uid="12345">
      <article-set>
         <article uid="87"><!-- omitted --></article>
         <article uid="88"><!-- omitted --></article>
         <article uid="89"><!-- omitted --></article>
      </article-set>
    </product>
    <product uid="7680">
        <!-- a.s.o -->
    </product>
  </chapter>
</catalogue>

In my programm I have to process most (or all) of the elements having a uid
attribute one by one, no matter what kind of element they are.
I could use "//*[@uid = myuid]" everytime, but for performance issues, I
want to cache the list of elements having a uid.

so I use "//*[@uid]" to get these elements. this xpath gives me a
XNodeSetBase.
in further expressions, I have to select a specific element in this nodeset
by its uid.

in Xalan-C API reference, I found XObjectPtr::rtree() returning a const
XalanDocumentTreeFragment &. This class is a subclass of XalanNode and could
be used as a context for the XPathEvaluator (the const can be casted away,
see  http://marc.theaimsgroup.com/?l=xalan-c-users&m=108145747222899&w=2
here )

but when I'm using this, a NULL-pointer is accessed. That's because
XObjectResultTreeFragProxyBase::getOwnerDocument()  always returns 0, so I
can't get the nodeset's owner document...

is there any way to store a nodelist returned by an XPath to be used as the
context on another XPath?

hope you can help me

bye
King Nak
-- 
View this message in context: http://www.nabble.com/Evaluating-XPath-on-NodeSet-tf2119970.html#a5846752
Sent from the Xalan - C - Users forum at Nabble.com.


Re: Update

Posted by King Nak <ki...@gmx.net>.
Thanks for your reply, but I found a workaround.

What I really need is select nodes by expressions like "//*[@uid = {some
value}]".
Since only the comparision value changes, I want to cache the result of
"//*[@uid]", and then get single nodes
from this cache only by the attribute value.

I'm now storing the nodes in a std::map.
given the expression "//*[@uid]", I store the value of the uid attribute as
the key and the XalanNode * as the value.

This works pretty good and I can also get single nodes from that map by
their attribute value, and that's all
I need right now.

bye
King Nak
-- 
View this message in context: http://www.nabble.com/Evaluating-XPath-on-NodeSet-tf2119970.html#a5979297
Sent from the Xalan - C - Users forum at Nabble.com.


Re: Update

Posted by David Bertoni <db...@apache.org>.
King Nak wrote:
> ok, I found an error in my second xpath expression.
> After getting the list of elements having a uid attribute, I used "//*[@uid
> = myuid]" on it.
> That started searching for elements at the root again, what I wanted to
> avoid.
> 
> Now I'm using "*[@uid = myuid]" instead, what also doesn't work properly.
> The problem is, that in XPath::findChildren, a tester is used to check all
> child elements of the context node
> if the element's names match (since I'm using a *, all elements match).
> It uses 
> child = context->getFirstChild() 
> to get the first element, and then 
> child = child->nextSibling()
> to iterate thru the elements.

That's because the expression "*[@uid = myuid]" is equivalent to 
"child::*[@uid = myuid]", which explains why the code works the way it does.

You probably want "self::*[@uid = myuid]" instead.

> 
> But this nextSibling() returns the next sibling in the original document,
> not the next element in the nodeset!

I don't understand what you're saying here.  The nodes are all nodes from 
the original document.

> so only the two products are found (because they're siblings in the
> document) but not the articles 
> (which would be in the nodeset, but are children of the products in the
> document)
> 
> is there a workaround for this problem?

It's not a problem -- Xalan-C is correctly evaluating the XPath expression 
you provided.  The problem is you don't have a clear understanding of how 
XPath works.

Instead of spending lots of time debugging Xalan-C and attempting to 
reverse-engineer behavior, you'd probably be better off figuring out what 
XPath expressions you need to get the results you want.

Dave

Update

Posted by King Nak <ki...@gmx.net>.
ok, I found an error in my second xpath expression.
After getting the list of elements having a uid attribute, I used "//*[@uid
= myuid]" on it.
That started searching for elements at the root again, what I wanted to
avoid.

Now I'm using "*[@uid = myuid]" instead, what also doesn't work properly.
The problem is, that in XPath::findChildren, a tester is used to check all
child elements of the context node
if the element's names match (since I'm using a *, all elements match).
It uses 
child = context->getFirstChild() 
to get the first element, and then 
child = child->nextSibling()
to iterate thru the elements.

But this nextSibling() returns the next sibling in the original document,
not the next element in the nodeset!
so only the two products are found (because they're siblings in the
document) but not the articles 
(which would be in the nodeset, but are children of the products in the
document)

is there a workaround for this problem?

bye
King Nak
-- 
View this message in context: http://www.nabble.com/Evaluating-XPath-on-NodeSet-tf2119970.html#a5848092
Sent from the Xalan - C - Users forum at Nabble.com.


Re: Evaluating XPath on NodeSet

Posted by David Bertoni <db...@apache.org>.
King Nak wrote:
> Hi!
> 
> I'm a novice to xalan and have a problem:
> I've got a big XML file representing a product calalogue. here an example
> excerpt:
> <catalogue>
>   <chapter>
>     <!-- some more hierarchy -->
>     <product uid="12345">
>       <article-set>
>          <article uid="87"><!-- omitted --></article>
>          <article uid="88"><!-- omitted --></article>
>          <article uid="89"><!-- omitted --></article>
>       </article-set>
>     </product>
>     <product uid="7680">
>         <!-- a.s.o -->
>     </product>
>   </chapter>
> </catalogue>
> 
> In my programm I have to process most (or all) of the elements having a uid
> attribute one by one, no matter what kind of element they are.
> I could use "//*[@uid = myuid]" everytime, but for performance issues, I
> want to cache the list of elements having a uid.
> 
> so I use "//*[@uid]" to get these elements. this xpath gives me a
> XNodeSetBase.
> in further expressions, I have to select a specific element in this nodeset
> by its uid.
> 
> in Xalan-C API reference, I found XObjectPtr::rtree() returning a const
> XalanDocumentTreeFragment &. This class is a subclass of XalanNode and could
> be used as a context for the XPathEvaluator (the const can be casted away,
> see  http://marc.theaimsgroup.com/?l=xalan-c-users&m=108145747222899&w=2

I don't know why you would want to cast a node-set to a result tree 
fragment.  You certainly wouldn't want to use this as the context for 
another evaluation, since it would yield no results.

> here )
> 
> but when I'm using this, a NULL-pointer is accessed. That's because
> XObjectResultTreeFragProxyBase::getOwnerDocument()  always returns 0, so I
> can't get the nodeset's owner document...
> 
> is there any way to store a nodelist returned by an XPath to be used as the
> context on another XPath?

Copy the nodes from the nodeset into your own container.  You can use 
std::vector<XalanNode*>, or Xalan-C's NodeRefList class:

NodeRefList  cachedNodes(xobj->nodeset());

Dave