The xsl copy function appears to deviate from the functional hierarchical pattern of the copy-of in that it doesn't assess the select condition (if condition is an XPath axes) before applying the function action.
so xsl:copy select="ancestor::*" will behave different than xsl:copy-of select="ancestor::*"
At least in XSLT 1.0, xsl:copy does not have a select attribute: it only copies the current node.
From the spec (emphasis mine):
The xsl:copy element provides an easy way of copying the current node. Instantiating the xsl:copy element creates a copy of the current node. The namespace nodes of the current node are automatically copied as well, but the attributes and children of the node are not automatically copied. The content of the xsl:copy element is a template for the attributes and children of the created node; the content is instantiated only for nodes of types that can have attributes or children (i.e. root nodes and element nodes).
Edit: XSLT2.0 xsl:copy behaves the same way
Well, copy and copy-of are intended to do very different things. copy always works on the current node and does not support the select attribute. See http://zvon.org/xxl/XSLTreference/Output/xslt_copy.html vs http://zvon.org/xxl/XSLTreference/Output/xslt_copy-of.html.
A select attribute is being added to xsl:copy in XSLT 3.0, to allow copying of nodes other than the context node (useful for example in a function). For XSLT 1.0 and 2.0, I really don't know what you mean.
Related
I have a xslt transformation from xml to pdf using apache fop. Whether is possible to add codnition to xslt transormation? I want to not display column in result pdf if all values in column equals zero. It's possible?
Yes, it is possible. In fact, you can do declarative/functional programming logic with XSLT using templates, functions and conditionals. Since you did not provide any example code, I will suppose that you have a table element in your xslt, and you want to show it only if there is some non-zero value to be displayed.
In this case, you should use an recursive template to walk along the list in your xml, and keep checking with XPath if the values are equal to zero. If you find zero, call this same template for the next value, if not, call the template that builds the table for you.
Notice that to use condition, you can use xsl:for-each, xsl:when or xsl:if elements to make the decision given the XPath expression. The xsl:template is used for iterating recursively with parameters, given that instance variables do not exist in xsl.
What I have so far can delete all the children of the actual node I want to delete but not the node itself.
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file("config/config.xml");
pugi::xpath_query query_network_last_run("//state[network/network_last_run='2']");
pugi::xpath_node_set network_last_run = query_network_last_run.evaluate_node_set(doc);
The part below removes specific parts -- but I want to delete the network based on a child value (network_last_run), not this child of it.
network_last_run[0].node().remove_child("network_gateway");
XML file structure
<root>
<state>
<network>
<network_last_run>2<network_last_run>
<network_gateway>192.168.3.1</network_gateway>
</network>
</state>
</root>
I tried to step back up using
network_last_run[0].node().parent().remove_child("network");
But it seems that only modifies the actual structure stored in memory, (removes the first one) and not the structure the query has.
I could probably do this in a for loop and use an if condition to check whether the child node value matches, but I would like to do it through a query if possible?
After playing around with it a bit, this is the solution I made (and I couldn't find an answer to this anywhere else so I figured I could just post it here)
Essentially it changes the name of the actual node in question. After that, it runs a query (the node set of which could be used in a for loop) and removes any child elements with the new name.
network_last_run[0].node().set_name("removal");
pugi::xpath_query query_removals("//state");
pugi::xpath_node_set removals = query_removals.evaluate_node_set(doc);
removals[0].node().remove_child("removal");
I have a stylesheet that I developed in version 1.0. I needed to convert to version 2.0 to take advantage of some additional features. Now however, when I use the following syntax I get all the results instead of just the first one. This worked in v1.0 but does not work in v2.0:
//elementName[1]
Is there a simple fix?
That XPath will return the same nodes in both versions (namely all the elementName elements in the document that are the first child with that name in their respective parent elements), but
<xsl:value-of select="//elementName[1]"/>
will give different results. In XSLT 1.0 the behaviour of value-of when given a set of nodes is to output the value of the first node in the set in document order and ignore the others, but in 2.0 it will output the values of all of them, separated by spaces. If you want to restrict to the first item in the sequence you should do so explicitly with (....)[1].
Yes, the fix is simple...
(//elementName)[1]
This will give you the first occurrence. Your previous xpath was every elementName that was the first elementName child of its parent.
A good example from the spec:
NOTE: The location path //para[1] does not mean the same as the
location path /descendant::para[1]. The latter selects the first
descendant para element; the former selects all descendant para
elements that are the first para children of their parents.
This isn't exactly what I want to do, but it's a simple case of the functionality I need. I want to alternate between processing nodes in one document and processing nodes in a temp document that was created during the processing of the original document. To do this, I want to "save" a node from the original document into the temp document so I can go back to it. I can easily "save" the node itself into the temp document, but being part of the temp document I can no longer do things like test if another node is an ancestor of that node in the original document.
I could imagine using generate-id to do this. I wouldn't save the node per se, but an id to it and then use the id to get back to the node within the original document. The problem with this approach is that I can't ask for the node whose generate-id is such and such. I could go through the tree and find it, but I'm looking for a simpler, faster access method.
Does one exist?
Thanks in advance.
Index every node of interest by its generate-id():
<xsl:key name="kNodeById" match="node()"
use="generate-id()"/>
and to get to the node by its id $vId:
key('kNodeById', $vId)
With XSLT, I am processing an xml file which might not have any nodes, other than the root. I want to output a special message on the html page for this case. I am using a for-each element to process the xml file. How do I check if the xml file has any actual nodes in it?
How Do I Check if an XML File Has No
Nodes?
By definition, any well-formed XML document contains at least a top element.
Therefore, any XML document contains some nodes -- there can't be an XML document that has no nodes.
I understand this question as asking: "How to determine that the top element of an XML document has no descendents?"
This is in fact an XPath question. This XPath expression:
/*[not(node())]
is true() exactly when the top element of the document has no child nodes (elements, text-nodes, processing instructions or comments).
The top element can still have attributes and it always has namespace nodes, but these two kinds of nodes are not considered to be exactly "children".
/*[not(node()) and not(#*)]
is true() exactly when the top element has no child nodes and no attributes.
/*[not(*)]
is true() exactly when the top element has no child element nodes (but it still can have text-node children, processing-instruction children and comment-nodes children).