[lxml-dev] xpath check, selective xslt
Hi everybody, a couple of questions: 1) is it possible to check if an element is selected by a particular xpath expression -without- checking if the element is part of the whole node-set returned by the expression evaluation? 2) let's assume we have an xslt-transformed ElementTree and that we add an untransformed branch to it. Is it possible to apply the same xslt transformation selectively, only to the added branch but not to the rest of the tree? Of course this wouldn't help in those situation where transformed(tree+branch) != transformed(tree) + transformed(branch). But excluding those cases, is there a way to do it? Thanks for your help! Manu
Hi, Emanuele D'Arrigo wrote:
1) is it possible to check if an element is selected by a particular xpath expression -without- checking if the element is part of the whole node-set returned by the expression evaluation?
Not that I'm aware of.
2) let's assume we have an xslt-transformed ElementTree and that we add an untransformed branch to it. Is it possible to apply the same xslt transformation selectively, only to the added branch but not to the rest of the tree? Of course this wouldn't help in those situation where transformed(tree+branch) != transformed(tree) + transformed(branch). But excluding those cases, is there a way to do it?
Why don't you apply the XSLT to the subtree *before* you insert it? Stefan
2009/9/28 Stefan Behnel <stefan_ml@behnel.de>
Emanuele D'Arrigo wrote:
1) is it possible to check if an element is selected by a particular xpath expression -without- checking if the element is part of the whole node-set returned by the expression evaluation?
Not that I'm aware of.
Darn! It'd be useful! To retrieve a whole node-set to check if one element is in it seems to be quite computationally expensive! Ok, I'll try to survive. =)
Why don't you apply the XSLT to the subtree *before* you insert it?
Because some transformations only apply "in context". I.e. suppose a transformation only applies to a <div> element if it is a child of the <body> element. I must first attach it to the <body> element and only then I can transform it. No? Manu
Emanuele D'Arrigo wrote:
2009/9/28 Stefan Behnel
Emanuele D'Arrigo wrote:
1) is it possible to check if an element is selected by a particular xpath expression -without- checking if the element is part of the whole node-set returned by the expression evaluation? Not that I'm aware of.
Darn! It'd be useful! To retrieve a whole node-set to check if one element is in it seems to be quite computationally expensive! Ok, I'll try to survive. =)
Well, what you *could* do is write an XPath extension function in Python that throws a dedicated SuccessException when called (so that the XPath evaluation terminates), and then catch that from your calling code that executes an XPath expression like this: //whatever[../parent and success(.)] Then give the exception an attribute that stores the element you found, and extract it where you catch the exception. I never tested that, but it should give you an XPath expression that shortcuts after the first hit (or N hits, if you add a counter to the function). Please report back if it works, that might make a nice FAQ entry.
Why don't you apply the XSLT to the subtree *before* you insert it?
Because some transformations only apply "in context". I.e. suppose a transformation only applies to a <div> element if it is a child of the <body> element. I must first attach it to the <body> element and only then I can transform it. No?
Ok, then why don't you apply it to the element *after* inserting it? Stefan
2009/9/29 Stefan Behnel <stefan_ml@behnel.de>
I never tested that, but it should give you an XPath expression that shortcuts after the first hit (or N hits, if you add a counter to the function).
It would certainly reduce computation time as in the best case the element in question is the first match. But it would still be expensive for the worst case scenario where the element to be matched is the last. And even the best case the element in question might be deep in the tree, requiring an expensive transversal anyway. No, I think it'd be good to implement some kind of reverse xpath evaluation, where the algorithm start from the last component of the xpath expression and works its way backward, from the element to be verified toward the root. I.e. given the tree: <alpha> <bravo /> <charlie> <delta /> </charlie> </alpha> and given the element <delta> and the xpath "/alpha/bravo/*/delta", the algorithm would first verify that the element's tag is "delta". Then it would check that <delta> has a parent, any parent. Then it would check that this parent is the child of "bravo", but as that's not the case the evaluation would return False: the element is not matched by the given xpath expression. I guess things might get tricky evaluating in reverse more complex cases and functions...
Why don't you apply the XSLT to the subtree *before* you insert it?
Because some transformations only apply "in context". I.e. suppose a transformation only applies to a <div> element if it is a child of the <body> element. I must first attach it to the <body> element and only then I can transform it. No?
Ok, then why don't you apply it to the element *after* inserting it?
IF the transformation is specific to the subtree sure, as the rest of the document would be unaffected. But the general case is that the transformation in question might be part of a bigger xslt file which might have been applied already to the rest of the document. Applying the same xslt file again to the whole document might have undesirable consequences. =? Manu
Emanuele D'Arrigo wrote:
I think it'd be good to implement some kind of reverse xpath evaluation, where the algorithm start from the last component of the xpath expression and works its way backward, from the element to be verified toward the root. I.e. given the tree:
<alpha> <bravo /> <charlie> <delta /> </charlie> </alpha>
and given the element <delta> and the xpath "/alpha/bravo/*/delta", the algorithm would first verify that the element's tag is "delta". Then it would check that <delta> has a parent, any parent. Then it would check that this parent is the child of "bravo", but as that's not the case the evaluation would return False: the element is not matched by the given xpath expression. I guess things might get tricky evaluating in reverse more complex cases and functions...
"might get tricky" is clearly the wrong wording here.
Why don't you apply the XSLT to the subtree *before* you insert it? Because some transformations only apply "in context". I.e. suppose a transformation only applies to a <div> element if it is a child of the <body> element. I must first attach it to the <body> element and only then I can transform it. No? Ok, then why don't you apply it to the element *after* inserting it?
IF the transformation is specific to the subtree sure, as the rest of the document would be unaffected. But the general case is that the transformation in question might be part of a bigger xslt file which might have been applied already to the rest of the document. Applying the same xslt file again to the whole document might have undesirable consequences.
Note how I wrote "element", not "document". Stefan
2009/9/29 Stefan Behnel <stefan_ml@behnel.de>
I guess things might get tricky evaluating in reverse more complex cases and functions...
"might get tricky" is clearly the wrong wording here.
Hehehe, fair enough. =)
Ok, then why don't you apply it to the element *after* inserting it? Note how I wrote "element", not "document".
I didn't know it was possible to apply an xslt transformation to an element! That's exactly what I was after! It's true, the API<http://codespeak.net/lxml/api/lxml.etree.XSLT-class.html>clearly states: "Calling this object on a tree or Element will execute the XSLT". I just had no idea about it because I only looked here<http://codespeak.net/lxml/api/index.html>and all examples refer to ElementTree objects being the input to XSLT objects. Might be good to add an Element example or change an existing one to handle an element. Thank you though, this is really good news! Manu
Emanuele D'Arrigo wrote:
I didn't know it was possible to apply an xslt transformation to an element! That's exactly what I was after! It's true, the API<http://codespeak.net/lxml/api/lxml.etree.XSLT-class.html>clearly states: "Calling this object on a tree or Element will execute the XSLT". I just had no idea about it because I only looked here<http://codespeak.net/lxml/api/index.html>and all examples refer to ElementTree objects being the input to XSLT objects. Might be good to add an Element example or change an existing one to handle an element.
Thank you though, this is really good news!
... not as good as that. I just checked, and it actually decouples the element from the rest of the document before running the XSLT. So that won't help in the case that the XSLT needs to refer to the ancestors. I wonder if it would make sense to disable the decoupling for plain Elements. The problem is that this might break code. OTOH, I expect little XSLT code to really depend on this, and it's easy to work around by wrapping the element in an ElementTree object. Stefan
2009/9/29 Stefan Behnel <stefan_ml@behnel.de>
... not as good as that. I just checked, and it actually decouples the element from the rest of the document before running the XSLT. So that won't help in the case that the XSLT needs to refer to the ancestors.
Darn!
I wonder if it would make sense to disable the decoupling for plain Elements. The problem is that this might break code.
Still, in-context sub-tree transformations doesn't seem to be a conceptually far fetched idea. Is the XSLT standard somehow forbidding it? If not, I think it'd be worth discussing it with the libxml people.
OTOH, I expect little XSLT code to really depend on this,
You are probably right -now-, but if the functionality becomes available I suspect it'd be quickly adopted for all sorts of unforeseen purposes.
and it's easy to work around by wrapping the element in an ElementTree object.
I didn't get this. The negatively important thing is that the element is not "in-context" when it's transformed. How would wrapping it in an ElementTree object help? Manu
Emanuele D'Arrigo wrote:
OTOH, I expect little XSLT code to really depend on this,
You are probably right -now-, but if the functionality becomes available I suspect it'd be quickly adopted for all sorts of unforeseen purposes.
and it's easy to work around by wrapping the element in an ElementTree object.
I didn't get this. The negatively important thing is that the element is not "in-context" when it's transformed. How would wrapping it in an ElementTree object help?
I meant the opposite: If we switch the way it works, I don't expect much code to break, and if it does, it'll be easy to fix by wrapping the element in an ElementTree object before passing it to the transformer. I'm not sure how hard this will be to implement, though. I didn't find an obvious function in libxslt that would take a context/start element in addition to the document to be transformed, so someone needs to investigate how libxslt works here (we normally call the xsltApplyStylesheetUser() function), and what it takes to start the transform from a different node (e.g. if calling xsltProcessOneNode() works out-of-the-box, or if there is a setup required beforehand). Could you file a feature request (i.e. bug) on the bug tracker for now? Stefan
2009/10/1 Stefan Behnel <stefan_ml@behnel.de>
I'm not sure how hard this will be to implement, though. I didn't find an obvious function in libxslt that would take a context/start element in addition to the document to be transformed, so someone needs to investigate how libxslt works here (we normally call the xsltApplyStylesheetUser() function), and what it takes to start the transform from a different node (e.g. if calling xsltProcessOneNode() works out-of-the-box, or if there is a setup required beforehand).
Could you file a feature request (i.e. bug) on the bug tracker for now?
Apologies, swamped by some tricky coding (still banging my head over it) I've been procrastinating on this issue. Of course I will. Are you referring to lxml's bug tracker or libxslt's bug tracker given that both lxml's functionality and limitations in this context arise from the latter? Manu
Emanuele D'Arrigo wrote:
2009/10/1 Stefan Behnel
I'm not sure how hard this will be to implement, though. I didn't find an obvious function in libxslt that would take a context/start element in addition to the document to be transformed, so someone needs to investigate how libxslt works here (we normally call the xsltApplyStylesheetUser() function), and what it takes to start the transform from a different node (e.g. if calling xsltProcessOneNode() works out-of-the-box, or if there is a setup required beforehand).
Could you file a feature request (i.e. bug) on the bug tracker for now?
Apologies, swamped by some tricky coding (still banging my head over it) I've been procrastinating on this issue. Of course I will. Are you referring to lxml's bug tracker or libxslt's bug tracker given that both lxml's functionality and limitations in this context arise from the latter?
lxml's bug tracker at launchpad. Thanks! Stefan
2009/10/21 Stefan Behnel <stefan_ml@behnel.de>
Could you file a feature request (i.e. bug) on the bug tracker for now?
I finally managed to stop procrastinating on this and added a blueprint rather than a bug: a bug would imply an error in lxml or libxslt but I suspect this issue might be something not even the XML and XSLT specifications consider and/or allow. https://blueprints.launchpad.net/lxml/+spec/lxml-in-context-validation-and-t... Hope it helps! Manu
participants (2)
-
Emanuele D'Arrigo
-
Stefan Behnel