On Mon, 15 May 2000, Kaiserovi wrote:
> 1) It should not be hard to add a function that will preserve the
> resulting tree, and another that will accept it as stylesheet/input. If
> that would suffice then it's OK.
>
> 2) It might be cool to be able to access these trees through a URI
> scheme, much as with the 'arg:' scheme (for accessing documents in
> memory). So you could call the processor say on 'tree:last-result'.
I definitely like that solution. The caching of XSL and XML documents can
be automatic (with perhaps some hints if the client "knows" there's no
value in keeping the XML document). The URI idea is indeed very nice.
> 3) I thought about your idea of a 'persistent Processor object' and I
> must say it does have several advantages. Thus a Processor would live
> longer than just one stylesheet application, and would have its own pool
> of ready-made trees, own processing options and registered handlers etc.
> There would possibly be one processor per thread (NOTE that Sablotron
> currently does not support multi-threading - would this work well with
> your project?).
I played around originally with a single Processor object, but I
eventually decided that it's kinda six of one half dozen of another. Given
the fact that a Process object contains information about its arguments
and stuff, and has to clean that up after each request, I undid my
"processor reuse" code and elected to use a static datalist instead. It's
much simpler.
I won't be using multithreading. The application would be fastcgi executed
by Apache, so one thread per process (but multiple processes per website).
> 4) A nice thing about this is that it fits in my favourite idea of
> debugging support (stepping through the stylesheet etc.)
Sorry, I'm not sure what you mean there.
> 5) Your hack: it's fine to see it's possible for someone to make his way
> through the code. However I can't tell what happened in this particular
> case without the patch. Would you please send it?
>
> The trees are left as they are after the parse.
The patch is attached. It also includes a patch/hack for sabcmd to make it
run 100 times. It has to run at least twice to test the caching
functionality, of course.
> 6) The objects: this is a bold concept, but the difficult part of it is
> probably how to define the methods. I think we'll need some details to
> decide how hard it would be to implement this. The variable references
> present no problem as they already are being expanded where necessary
> (e.g. in <xsl:element name="{$whats-the-name}"/>).
The implementation of the extension tags would be the problem of the
extension library. What I had in mind was that sablotron would see a tag
it doesn't understand (in the XSL file) and send a tree of tags to a
callback function. This callback function would implement the
"xsl:dumpmethod" tag and friends.
For an initial implementation, though, the function could just send the
contents of the tag, with an array of name/value pairs for the attributes,
and forget about the tree underneath.
> Steve Willer wrote:
> >
> > On Mon, 15 May 2000, Kaiserovi wrote:
> >
> > > Well, we are aware of things that should be optimized in the code; with
> > > some of them, it would not be difficult, and I expect a significant
> > > improvement in performance when that is done. However, it takes some
> > > time, and since Sablotron now runs at "reasonable" speed (at least for
> > > us), I think it's better to try and fill in the missing functionality
> > > first.
> >
> > Yes, although from my point of view I have to get a website up and
> > running relatively soon (6 weeks), and I want to use a
> > multiple-transformation architecture. Page building should be fairly fast.
> >
> > Architecturally, it would definitely be best if the "result" could
> > optionally be a parse tree, which I can feed into the next process call as
> > the XML input. I believe this is a relatively small API change (which I
> > could perhaps make myself). Then there's the caching thing, and
> > extensions...
> >
> > > You're right. The idea is that one Processor object corresponds to a
> > > single run of a stylesheet on a document. On the other hand, the cache
> > > would have to be persistent, kind of global within the shared library.
> > > That's one possibility anyway.
> >
> > Yep. I started by making the Process object's datalist member a
> > module-level static in proc.cpp. Then I killed the datalines.freeall()
> > call. I tried running the same XML/XSL combination multiple times in one
> > sabcmd call, but it found the cached result tree on the second try and got
> > mad. So I changed makeTreeForURI() to call datalines.freerm() instead of
> > exiting. It's a hack, I know, because maybe we would want to hold on to
> > the result tree. But I wanted to try it.
> >
> > An interesting result: It was a lot faster for 100 loops (175ms per loop
> > vs 520ms), but the output had only ctext and no tags. Is the XML or XSL
> > tree being modified in-place during processing? If you want, I can send
> > you a patch of what I've done so far, to play with it. I'm sure I'll
> > continue to experiment, as I don't have a lot of time to come to a
> > decision.
> >
> > > > My second question is about extension support. I need to figure out a way
> > > > to get my system of XSL files somehow instantiating objects and making
> > > > method calls for those objects. I don't want to do this with Cocoon-style
> > > > full language embedding, but figured I could do it with a few extra tags
> > > > in the XSL file, if there was support for expanding out XSL variable
> > > > references within the tags. So my question, for those who know the
> > > > architecture better than I, is: How hard would this be? Are there any
> > > > plans for it? Could I hack it in easily?
> > >
> > > Ugh. I'm probably getting this wrong. What do you mean by "expanding out
> > > XSL variable references within the tags", something like
> > >
> > > <my_tag_$name> expanded as, say, <my_tag_JOE> ?
> >
> > No. XSLT already has a variable capability; I wanted to extend that.
> > Here's a not-well-planned example:
> >
> > <xsl:template match="/">
> > <xsl:variable name="website">
> > <xsl:object name="Website" website_id="{input/website_id}"/>
> > </xsl:variable>
> > <xsl:dumpmethod variable="website" method="search_products"
> > text="{input/formdat/text}"/>
> > </xsl:template>
> >
> > This example code would instantiate a Website object, giving its
> > constructor a website_id parameter, and putting the result into the XSL
> > variable "website". Then it would call
> > website->search_products({input/formdat/text}) and dump the resulting
> > hashtree or whatever into an XML tree. I would also want to be able to do
> > something like:
> >
> > <xsl:dumpmethod variable="product" method="set_website"
> > website_id="{$website}">
> >
> > See, all of this would involve expanding any variable or tag references
> > inside the tag, then passing it on to some extension callback function,
> > and then working with the results in whatever way it needs to (like
> > putting the results into another variable). I realize my scheme isn't
> > well-formed, cuz you can't make a DTD for it; I haven't thought it all
> > through in an XML way yet.
>
>
>
? addr_book1.xml
? addr_book1.xsl
? bin
? include
? lib
? sablot.log
? Expat/bin
? Expat/lib
? Expat/Linux/libxmltok.so.1.0
? Expat/Linux/libxmlparse.so.1.0
? Sablot/Linux/libsablot.so.0.3
? Sablot/Linux/sabcmd
Index: Sablot/proc.cpp
===================================================================
RCS file: /usr/share/cvsroot/sablotron/Sablot/proc.cpp,v
retrieving revision 1.1.1.1
diff -u -w -r1.1.1.1 proc.cpp
--- Sablot/proc.cpp 2000/05/14 23:17:40 1.1.1.1
+++ Sablot/proc.cpp 2000/05/15 16:59:23
@@ -43,7 +43,9 @@
Str ns_XSL = "http://www.w3.org/1999/XSL/Transform";
+DataLinesList datalines;
+
/*****************************************************************
R u l e I t e m methods
*****************************************************************/
@@ -178,7 +180,7 @@
cdelete(styleSheet);
*/
cdelete(vars);
- datalines.freeall(FALSE);
+ //datalines.freeall(FALSE);
argList.freeall(FALSE);
if (!situation.isError())
assert(modes.isEmpty());
@@ -542,8 +544,7 @@
eFlag Processor::readTreeFromURI(Tree*& newTree, Str& location, Str& base,
Bool isXSL)
{
- Str
- absolute;
+ Str absolute;
makeAbsoluteURI(location, base, absolute);
newTree = datalines.getTree(absolute, isXSL, DLMODE_READ);
if (!newTree)
@@ -554,9 +555,11 @@
eFlag Processor::makeTreeForURI(Tree*& newTree, Str& location, Str& base)
{
Str absolute;
+ int pos;
makeAbsoluteURI(location, base, absolute);
- if (datalines.getTree(absolute, FALSE, DLMODE_WRITE))
- Err1(E1_CANNOT_WRITE, absolute);
+ if ((pos = datalines.findNum(absolute, FALSE, DLMODE_WRITE)) != -1)
+ datalines.freerm(pos, FALSE);
+ //Err1(E1_CANNOT_WRITE, absolute);
newTree = new Tree(absolute, FALSE);
DataLine *d = new DataLine;
newTree -> dline = d;
Index: Sablot/proc.h
===================================================================
RCS file: /usr/share/cvsroot/sablotron/Sablot/proc.h,v
retrieving revision 1.1.1.1
diff -u -w -r1.1.1.1 proc.h
--- Sablot/proc.h 2000/05/14 23:17:40 1.1.1.1
+++ Sablot/proc.h 2000/05/15 16:59:23
@@ -159,7 +159,6 @@
PList<QName*> modes;
StrStrList
argList;
- DataLinesList datalines;
};
#endif //ifndef ProcHIncl
Index: Sablot/sabcmd/sabcmd.c
===================================================================
RCS file: /usr/share/cvsroot/sablotron/Sablot/sabcmd/sabcmd.c,v
retrieving revision 1.1.1.1
diff -u -w -r1.1.1.1 sabcmd.c
--- Sablot/sabcmd/sabcmd.c 2000/05/14 23:17:40 1.1.1.1
+++ Sablot/sabcmd/sabcmd.c 2000/05/15 16:59:23
@@ -63,7 +63,7 @@
int main(int argc, char *argv[])
{
- int firstEq, i, pos,
+ int firstEq, i, pos, x,
paramsI = 0, argsI = 0;
char *paramsToPass[2 * ARG_OR_PAR_MAX + 2],
*argsToPass[2 * ARG_OR_PAR_MAX + 2],
@@ -89,6 +89,8 @@
argsToPass[2 * argsI] = NULL;
paramsToPass[2 * paramsI] = NULL;
+ for (x = 0; x < 100; x++) {
+
if (SablotProcess(argv[1],
firstEq <= 2 ? (char*)"file://stdin" : argv[2],
firstEq <= 3 ? (char*)"file://stdout" : argv[3],
@@ -99,6 +101,7 @@
fprintf(stderr, "output buffer sent to stdout\n");
puts(resultArg);
SablotFree(resultArg);
+ }
}
freefirst(argsToPass);