You are viewing a plain text version of this content. The canonical link for it is here.
Posted to j-users@xalan.apache.org by Christoffer Dam Bruun <cd...@flyingpigs.dk> on 2009/06/24 10:29:00 UTC

Howto implement a node index extension to be shared across transform invocations on the same source document (DOMSource)

Hi,

I have a webapplication  where I hold a large XML tree in memory.  On 
this tree
I perform several transforms as response to user requests. 
Each transform declares a <xsl:key> that serves as an index for 
important nodes in the tree.

However, it is expensive to calculate this key and it should be possible 
to reuse it since I know that the source tree has not been modified.


Since modifying the Xalan <xsl:key> implementation is difficult, I tried 
my luck with a
 Java extension approach where I simply store selected nodes in a 
HashMap outside
the transform.

However, when I return a node from the extension then Xalan goes boom! 
if the node
was added in a previous transform.

Does anyone know how to make this work ?


Best regards
Christoffer Dam Bruun

// The Java extension

public class ElementIndex {

   public static Map<String, SingleIndex> indexes = new HashMap<String, 
SingleIndex>();

   public static Node key(String indexId, String key) {
       NodeSet ns = new NodeSet();
       SingleIndex idx = indexes.get(indexId);
       if (null == idx) {
           System.err.println("idx er null");
       }
       List<Node> nl = idx.get(key);
       if (null == nl) {
           return null;
       }
       return nl.get(0);
   }

   public static int add(ExpressionContext ec, String indexId, String 
key, NodeList nodes) {
       SingleIndex idx = indexes.get(indexId);
       if (null == idx) {
           idx = new SingleIndex();
           indexes.put(indexId, idx);
       }
       for (int i = 0; i < nodes.getLength(); i++) {
           Node tmp = nodes.item(i);
           idx.put(key, tmp);
       }
       return 0;
   }

   public static int remove(String indexId) {
       return 0;
   }

   public static int clear(String indexId) {
       return 0;
   }

   public static class SingleIndex {
       String idxName;
       Map<String, ArrayList<Node>> idx = new HashMap<String, 
ArrayList<Node>>();

       public List<Node> get(String key) {
           return idx.get(key);
       }

       public void put(String key, Node n) {
           List<Node> nl = idx.get(key);
           if (null == nl) {
               nl = new ArrayList<Node>();
               idx.put(key, (ArrayList<Node>) nl);
           }
           nl.add(n);
       }

       public void remove(String key, Node n) {
           List<Node> nl = idx.get(key);
           if (null == nl) {
               return;
           }
           nl.remove(n);
       }
   }
}


// Adding to the index:
<xsl:value-of select="idx:add('nidkey', @nid,current())"/>


// Getting nodes from the index
<xsl:variable name="task" select="idx:key('nidkey',@nid)"></xsl:variable>






Re: Howto implement a node index extension to be shared across transform invocations on the same source document (DOMSource)

Posted by Michael Ludwig <ml...@as-guides.com>.
Christoffer Dam Bruun schrieb:
> Michael Ludwig skrev:
>> Could XSLTC (which I don't have any experience with yet) be used to
>> make the <xsl:key> persist? Hmm, maybe the <xsl:key> would persist -
>> but that probably would still require its execution on a document
>> instance.
> I don't think XSLTC would make any difference since the XSLT processor
> cannot know that the XML document has not been modified since the key
> was last calculated- only I as the programmer knows that.

I see, you'd need the lookup table resulting from applyint the <xsl:key>
on the document, and that doesn't seem to be available.

>> Could you use the ID feature built into XML to achieve what you want?
> I have looked at it - the problem is that I also use an one-to-many
> reverse-id lookup e.g.:
> "All elements that refer to the element with this @id"
> and I don't think I can cram that into the builtin ID feature.

Can't think of a way to achieve that either. Sounds like you really need
<xsl:key>.

I've never used this, but if all else fails, you might want to take a
look at VTD-XML:

http://vtd-xml.sourceforge.net/

Michael Ludwig

Re: Howto implement a node index extension to be shared across transform invocations on the same source document (DOMSource)

Posted by Christoffer Dam Bruun <cd...@flyingpigs.dk>.
Michael Ludwig skrev:
> Christoffer Dam Bruun schrieb:
>
>> I have a webapplication  where I hold a large XML tree in memory.  On
>> ...
>
> Could XSLTC (which I don't have any experience with yet) be used to make
> the <xsl:key> persist? Hmm, maybe the <xsl:key> would persist - but that
> probably would still require its execution on a document instance.
I don't think XSLTC would make any difference since the XSLT processor 
cannot know that the
XML document has not been modified since the key was last calculated- 
only I as the programmer knows that.
>
> Could you use the ID feature built into XML to achieve what you want?
I have looked at it - the problem is that I also use an one-to-many 
reverse-id lookup e.g.:
"All elements that refer to the element with this @id" 
and I don't think I can cram that into the builtin ID feature.

Christoffer Bruun


Re: Howto implement a node index extension to be shared across transform invocations on the same source document (DOMSource)

Posted by Michael Ludwig <ml...@as-guides.com>.
Christoffer Dam Bruun schrieb:

> I have a webapplication  where I hold a large XML tree in memory.  On
> this tree I perform several transforms as response to user requests.
> Each transform declares a <xsl:key> that serves as an index for
> important nodes in the tree.
>
> However, it is expensive to calculate this key and it should be
> possible to reuse it since I know that the source tree has not been
> modified.

Could XSLTC (which I don't have any experience with yet) be used to make
the <xsl:key> persist? Hmm, maybe the <xsl:key> would persist - but that
probably would still require its execution on a document instance.

Could you use the ID feature built into XML to achieve what you want?

<!ATTLIST elm id ID #IMPLIED>

Wouldn't that persist between invocations?

That would make for efficient lookup; however, it would constrain the
values of elm/@id to what's valid for an ID type attribute.

Also, see the following thread related to an XSLT feature related to
ID-typed attributes:

Xalan-J 2.7.1: document() function disregards URI fragment identifier
http://markmail.org/thread/ept5ifkshhjoagf3

Lots of "could" and "would" here. One more: It would be great to get
input from the experts on this one.

Michael Ludwig