XSLT counting child nodes with a set of filter - xslt

I want to remove all spaces with normalize space() while counting all nodes and use a Filter on those.
What I want is something like this:
<{namespace}:Text>
<{namespace}:Info>This is text from Info Node</{namespace}:Info>
Here is text which i want to find
</{namespace}:Text>
I want to count all children from {namespace}:Text , but i want to ignore {namespace}:Info and [namespace}:otherelement and the content of those should be ignored too.
I want as a result from count a 1 so that I know there are nodes which I have to process, so I can call templates workwithcontent or workwithempty.
But of course I do want to find other nodes too which don't fit the filter.

It sounds like you want something like
<xsl:template match="{namespace}:Text">
<xsl:variable name="count"
select="count(child::node()[not(self::{namespace}:Info)])" />
...
This will count all child nodes of <{namespace}:Text>, including both text and element nodes, except for <{namespace}:Info> elements.
If that's not what you need, please clarify.
The child:: axis is optional, but makes it more obvious what the XPath expression will select.

Related

XSLT select unknown nodes

I have some trouble with a special XML-document.
The XML has only 3 nodes like the below the example:
<solidName>
<unknownNodeName>
<everytimeTheSame>blablabla</everytimeTheSame>
<everytimeTheSame2>blablabla</everytimeTheSame2>
<unknownChildNodeName>
<everytimeTheSame>blablabla</everytimeTheSame>
<everytimeTheSame2>blablabla</everytimeTheSame2>
</unknownChildNodeName>
</unknownNodeName>
</solidName>
I need to select the unknownNodeName and the unknownChildNodeName to use the function
<xsl:value-of select="everytimeTheSame"/> and so on. I tried to use a for-each select function, but I found no way to get the unknow Name of the node.
Are there any possibilities for my problem? Is it possible to say <xsl:for-each select ="NodeNumberX"> or things like that <xsl:for-each select ="/*/*">
to use the function and so on
is not a good description of what you want to do.
Selecting "unknown nodes" (i.e. nodes whose name you do not know, but you do know their position in the document's tree) is trivial by using the * symbol in an XPath expression, possibly combined with a positional predicate.
For example:
/*/*/*[2]
will select the <everytimeTheSame2> element in your example.

Refer to specific cell in xslt import/export filter for Calc

I am using xslt filter for importing/exporting data from Calc worksheet. Is it possible to refer to a specific cell address ? For example, if we want to export data from cell B2, how do we refer to this cell address in export xslt ?
Without knowing much about Openoffice or their xslt filter function, I can tell you that you're probably going to need a fairly simple XPath to reference a specific Cell's data - I doubt it would be as simple as calling getCell('B2') unless they have provided you with some custom xslt functions (I'm assuming they've put you in a raw XSLT environment).
Anyway, I think this question may be more about XSLT and xpath, than it is about openoffice. With that in mind, I'm going to fashion my own sample xml and examples and hopefully that will be enough to get you started.
For an input xml that looks something like this:
<ooo_calc_export>
<ooo_sheet num="1" name="sheet1">
<ooo_row num="2">
<fisrtCell>Oh</firstCell>
<secondCell>Hai</secondCell>
<thirdCell>There</thirdCell>
</ooo_row>
<ooo_row num="3">
<fisrtCell>Oh</firstCell>
<secondCell>Hello</secondCell>
<thirdCell>Back!</thirdCell>
</ooo_row>
</ooo_sheet>
</ooo_calc_export>
An absolute XPath to access cell B2's data would look like this ooo_calc_export/ooo_sheet/ooo_row[#num='2']/secondCell/text()
But the above is an absolute path and in XSLT, we would often author relative xpaths as we are in the midst of processing a document. Imagine you're in a template which matches on the ooo_calc_export node and you wanted to store Cell B2's data in a variable for later use. Consider this example:
<xsl:template match="/ooo_calc_export">
<!-- a relative xpath does not being with a forward slash -->
<xsl:variable name="B2" select="ooo_sheet/ooo_row[#num='2']/secondCell/text()" />
</xsl:template>
Now lets imagine you wanted a template to match on the cell B2 node itself:
<xsl:template match="ooo_row[#num='2']/secondCell">
<!-- a relative xpath does not being with a forward slash -->
<xsl:variable name="B2_text" select="text()" />
</xsl:template>
This is a good tutorial on XSLT to get you started. Also, the W3 Schools references on XPath and XSLT aren't the worst.

ancestor-or-self wont select self

There should be a fairly simple solution but I cant get it to work.
This is my code:
<xsl:value-of select="$currentPage/ancestor-or-self::* [#isDoc and backgroundImage != '' and string(umbracoNaviHide) != '1']/backgroundImage"/>
What I want is if the node has a background image attached to it by the property backgroundImage, then use that image. If it does not have an background image, check the parent node for the background image and use that.
What happends for me is that it always checks for the parents background image, even if the node itself has a background image.
Any suggestions on how I could resolve this?
Update
<site id="1000" ...>
<backgroundImage>/media/image.jpg</backgroundImage>
<textPage id="1001" ...>
<backgroundImage>/media/image2.jpg</backgroundImage>
</textPage>
<textPage id="1002" ...>
<backgroundImage />
</textPage>
</site>
If I'm on <textPage id="1002"> where backgroundImage is null I would like to get image.jpg from <site id="1000">.
If I'm on <textPage id="1001"> where backgroundImage is not null, I would like to get image2.jpg.
Numeric predicates applied to an XPath address are processed in proximity order, while the resulting nodes from the addressed are handed to an XSLT processor in document order.
In XSLT 1.0, <xsl:value-of> returns the first of the nodes returned, so the first of the nodes in document order, so if you are addressing all of the ancestors or self with given properties, you will get the farthest one, not the closest one. In XSLT 2.0 you get all of them.
Since predicates are applied in proximity order, just use:
<xsl:value-of select="$currentPage/ancestor-or-self::*[...whatever...][1]"/>
... to get the closest of those with the properties indicated by the "whatever" predicate.
The reason [last()] works in Frank's solution is that the parentheses return the enclosed nodes in document order, so the closest one of those will be the last.
But from a semantics perspective, I think it reads better to simply address the first in proximity order.
Try
<xsl:value-of select="($currentPage/ancestor-or-self::* [#isDoc and backgroundImage != '' and string(umbracoNaviHide) != '1'])[last()]/backgroundImage"/>
You get the sequence of all ancestors including the current element that fulfill the conditions with your code. If you add the last() function, you will get the last item of this sequence that fulfills the condition.

xsl return the dynamic node value

hello:
do you guys know how to display the nodes' value which the nodes name are dynamic, for example, the nodes name is like x1, x2, x3... the number 1, 2 ,3 depends on the returns of the table.
i can get the node name using the loop, but only can get the name, even xsl:value-of select="$nodename", returns the nodename, not the value
As #Dimitre said, you haven't given us much specific information to work with, but in general you can use this to select elements whose names are determined at run time:
<xsl:value-of select="*[local-name() = $someDynamicValue]" />
You can also use name(), but local-name() ignores the namespace prefix, which usually makes things easier.
If you'd like more detailed help, please provide your sample input XML (especially the "returns of the table"), and the XSLT you've tried so far; and preferably, a sample of desired output XML.

XSL: Combining grouping and call-template

I've read with interest the techniques available on the web to extract a unique list of items from a XML file containing duplicates using XSL.
These range into 2 categories:
1) The Muenchian method (example: http://www.jenitennison.com/xslt/grouping/)
2) Or the previous-sibling look-up
These both rely on an XPath expression to select the data to group by.
However, in the XML file that I'm trying to work out, the data is not present "natively" in the XML file. I am using a xsl:template to compute some aggregated data from my elements. And I would like to group based on the aggregated data.
For example I have:
<filmsreview>
<record><data name='movie'>Star Wars</data><data name='ratings'>John:Good, Mary:Good</data></record>
<record><data name='movie'>Indiana Jones</data><data name='ratings'>John:Good, Mary:Bad, Helen:Average</data></record>
<record><data name='movie'>Titanic</data><data name='ratings'>John:Bad, Helen:Good</data></record>
</filmsreview>
I know that the structuration of data is not perfect and that by creating sub-elements I could do something easier, but I cannot change the data source easily, so let's take this as a challenge.
And I would like to build a recap where I have John's distinct ratings:
John's ratings:
Good
Bad
I have a xsl:template that can take a record element and return John's rating for this record:
Example:
<xsl:template name="get_rating">
<xsl:param name="reviewer" />
<!-- I use some string manipulation, and xsl:value-of to return the review for John-->
</xsl:template>
I can just call it under a xsl:for-each to get the exhaustive list of John's review. But I cannot combine this call with any of the methods to get unique values.
Do I have to use an intermediary XSL to convert my XML file to a more structured way? Or can I do in a single step?
Many thanks
Gerard
Hmm... This should be possible using xslt variables and the nodeset method, perhaps something like this:
<xsl:variable name="_johnsRatings">
<xsl:apply-templates select="/" mode="johnsRatings" />
</xsl:variable>
<xsl:variable name="johnsRatings" select="msxsl:node-set($_johnsRatings)" />
<xsl:template match="/" mode="johnsRatings">
<Ratings>
<xsl:for-each select="/filmsReview/record/data[#name='ratings']">
<Rating><xsl:call-template name="get_rating" /></Rating>
</xsl:for-each>
</Ratings>
</xsl:template>
At this point, it should be possible to query the $johnsRatings variable using standard XPath queries, and you can use either of the two methods you mentioned above to retrieve unique values from it...
Hope that helps
EDIT:
I don't know what XSLT engine you are using, I assumed you have access to the msxsl:node-set() function. However, most XSLT processors have similar methods, so you might have to search around for an equivalent method in your processor