Re: [xsl] a weird bug today, tree seems to change mid transform

Subject: Re: [xsl] a weird bug today, tree seems to change mid transform
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Sat, 08 Sep 2007 16:03:00 +0200
bryan rasmussen wrote:
I don't have access to the code that is doing it, but it
seems evident that somehow it is tampering with the DOM during the
transform.

'seems' evident, yes. But you mentioned a couple of things in this post that make me second your thoughts on this. Read on... ;)


This does not seem to be something someone would want to do
therefore I suppose a bug.

the question might be: whose bug is it? Again, read on, I'll explain my thoughts below ...



from the second post I mentioned that I did: <xsl:copy-of select="self::*"/>

and got
<x x="Andet">...

do you mean I should have done a mode like apply-templates
select="self::*" mode="copy" and then copy the structure out in the
mode template? If this gave a different result from copy-of select I
would still assume there was something messed up going on.

No, you already did what I meant, I overlooked that bit.


The transformation was incredibly simple. There was no node-set there
were no includes imports no document function nothing external to the
transfrom that basically transformed an x element to a button with the
value of the x attribute as the button text.

However, later on you mention ASP. Can you change the ASP? Can you be certain that there is no post-processing going on? There's a way to find this out if you don't have access to the code, but it requires a bit of originality (and possibly a second web server). Read on, I'll explain in a bit.


Additional question: where do you see your results? In a log file, on a web page, in an intermediate file you created for this purposes? If it is on a web page, make sure you view the original code and not what the browser makes of it (I assume that 'x' is actually some other nodename in your real code).


x=<xsl:value-of select="@x"/> caption=<xsl:value-of select="$caption"/> capt2=<xsl:value-of select="$capt2"/> <xsl:copy-of select="self::*"/>

I get
x=Andet
caption=more
capt2=More <-- can things get any weirder!!?
<x x="Andet">..</x>

<SNIP ... />

If I copy the XML out, the x element and run it on it I get

x=Andet
caption=andet
capt2=pndet
<x x="Andet">...</x>

What precisely do you mean with "copy xml out"? Considering the nature of the problem it is probably wise to explain it very explicitly... ;)


(and I have a hard time figuring
out how you can force this kind of thing to happen)

not too hard, really... but read on ... ;)



Okay the input XML is dynamically generated, but if they modify
attributes on the fly by the DOM will this affect the transformation
mid-transform. I've done alteration of both input and XSL Doms and
never experienced an affect mid-transform. This would be what I would
think was a bug in a processor, or can one in fact structure the code
in such a way that it will cause this. The application is written on
the server in ASP, if you or anyone can think of an example doing this
kind of restructuring mid-transform.

This is the point I wanted you to read on to ;)
Ok, this might be the root of your problem: ASP. You don't mention what version of ASP or whether it is ASP.NET. But in general, when you have something heavy going on like an XSLT transformation, you want the inside the session handler, static, but local to the current session object (I don't know how much you know of ASP, just fire your questions when I start to sound vague). This is similar to a singleton object and may or may not be subject to lazy initialization. Now the problem in ASP is with the locking of objects and releasing them. If you don't get this right, it is very well possible that different threads access the same objects on the same time. This, again, may or may not cause exceptions, or just unexpected behavior (i.e., if one threads *reads* a property and another thread *writes* a property, when this is after one another it does not need to cause an exception).


From what I know of MSXML is that it does not copy the entire DOM object for processing. It must however be a freethreading object. I can go on and on about this, but it is probably better to first find out whether this really is your problem. I hope you are able to change the code a bit, or that you can introduce a test page. In this test page, put everything in the page onload handler, and with everything I mean: getting the preprocessed and auto-generated DOM object, processing it by your XSLT and then viewing the results.

Some of these thoughts are backed up by a bug that does bad reference counting on the objects (meaning: it is not clear to the object server whether to free an object or not). Though the subject is different, it might have something to do with one another... http://support.microsoft.com/kb/919587/en-us

This might however be a bit too far-fetched, especially if you cannot change this code or if you are not an ASP programmer. The above scenario may happen quite easily, but a good XSLT processor should prevent it by locking the object (otherwise the "no side effects" rule is being violated, as is accessing the same node twice, which should yield the same result during one transformation cycle).

An alternative is the following. First find out whether the DOM really *is* changed during the process or during calling the translate() function (who knows, maybe the translate function releases the lock and then acquires it again and meanwhile the DOM is changed?!?!?!? Quite unlikely, but hey, your problem is unlikely). You need some ingredients for this operation, but it will give you some insight in what is happening under the hood.

1. Make some web server (preferably NOT inside the same IIS) available, it must be possible to access it from your code
2. Create one simple service, possibly with SSI, or some other technique you are familiar with, all it does is returning whatever is in the query string of the url as an xml document (i.e., if the url is http://mywebserver/mypage.asp?thestring, it should return '<root>thestring</root>' and only that).
3. This service should log locally everything it gets
4. Change your testing code as follows:


<xsl:variable name="caption"
select="translate(document(concat('http://yoururl?', @x))/root
,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'')"/>
<xsl:variable name="capt2" select="translate(document(concat('http://yoururl?', @x))/root
,'A','p')"/>

x=<xsl:value-of select="document(concat('http://yoururl?', @x))/root"/>
caption=<xsl:value-of select="$caption"/>
capt2=<xsl:value-of select="$capt2"/>
<xsl:copy-of select="self::*"/>



Ok, in all honesty? I hope you don't have to go that far.... I just reread in your original post that you have to use just about the most ancient XLST parser in history, msxml 2 (unless you mean it is actually 3.0 or 6.0, read the article under 2 below), loaded with bugs and problems that microsoft does not address anymore because they want you to upgrade... From that, I guess you do not use ASP.NET, but old ASP. You have a legacy that is crap (pardon my English) and you seem to have to deal with it.

Two other options (yes, I'm adrift lol):

1. Stop reading the attribute, add it into a variable and force it to a string: <xsl:variable name="x" select="string(@x)" />
2. If you are not allowed to move on from the 1997 code of MSXML2, let them read this article by Microsoft blog: http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx, and ask them if you can try for one day the same code on an installation with MSXML3 or MSXML6 (the latter may require you to set security options for using the document() function or for using msxml scripting).




Sorry for the long story. I hope there's something worthwile in the silly suggestions I made, but hey, you have a silly problem ;)

Hope you find out what actually happened,

Cheers,
-- Abel Braaksma

Current Thread