This one I really think is not possible to solve through XSLT, so that I will have to do something with JS or just do not implement.
But before giving up, of course I have to post here to see if I am wrong and XSLT can do this kind of logic.
EDIT: now I’m starting to see that it is possible, getting closer
EDIT2: I have to correct a mistake in the XML code provided. The solution should be able to handle multiple nodes with the same values.
The concept is that I need to re-format the code including empty tags that reflect the total number of different values. Difficult to explain, much easier to understand looking at the code.
Initial XML code
<data>
<prot seq="AAA">
<node num="4">1345</node>
</prot>
<prot seq="BBB">
<node num="7">6666</node>
</prot>
<prot seq="CCC">
<node num="10">3e33</node>
</prot>
<prot seq="DDD">
<node num="4">1345</node>
</prot>
<prot seq="EEE">
<node num="10">3e33</node>
</prot>
</data>
And the wished output
<root>
<prot seq="AAA">
<node num="4">1345</node><node num="7">-</node><node num="10">-</node>
</prot>
<prot seq="BBB">
<node num="4">-</node><node num="7">6666</node><node num="10">-</node>
</prot>
<prot seq="CCC">
<node num="4">-</node><node num="7">-</node><node num="10">3e33</node>
</prot>
<prot seq="DDD">
<node num="4">1345</node><node num="7">-</node><node num="10">-</node>
</prot>
<prot seq="EEE">
<node num="4">-</node><node num="7">-</node><node num="10">3e33</node>
</prot>
</root>
Any idea?
Thanks!
EDIT3: from Dimitri solution, I’ve ended up with this simplified solution
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kNodeByNum" match="/data/prot/node" use="@num"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="/data/prot"/>
</root>
</xsl:template>
<xsl:template match="/data/prot">
<xsl:variable name="current_num" select="node/@num"/>
<xsl:variable name="current_value" select="node"/>
<prot seq="{@seq}">
<xsl:for-each select="/data/prot/node[
generate-id()
=
generate-id(key('kNodeByNum', @num)[1])
]">
<xsl:choose>
<xsl:when test="@num = $current_num">
<node num="{@num}"><xsl:value-of select="$current_value"/></node>
</xsl:when>
<xsl:otherwise>
<node num="{@num}">-</node>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</prot>
</xsl:template>
</xsl:stylesheet>
However, this code also cannot handle the number of nodes in firefox and goes in a forever-like loop (and I have to force firefox to close).
But I am thinking that this has nothing to do with the number of nodes but that there is something wrong with the code (?)
Here is a short and simple (no
xsl:choose,xsl:whenandxsl:otherwise) solution:when this transformation is applied on the provided XML document:
the wanted, correct result is produced:
Explanation:
We use and override a modified version of the identity rule — one which accepts and passes a parameter named
$pParent.The parameter
$pParentcontains thenodeelement that issuedxsl:apply-templates, part of which is the processing of the current node.We have two templates that override the identity rule. The first overriding template matches any
protelement. It is almost identical to the identity rule, but it sets the$pParentparameter with a meaningful value (this node itself).The second overriding template matches any text node that is a child of any
nodeelement. Here, depending on whether or not the value of$pParentidentifies the grandparent of the matched text node, we output respectively, the value of the text node or just"-".The decision what to output is done without using any explicit conditional instruction. Instead, we use the XPath
concat()function with two arguments, exactly one of which is a non-empty string. To assure this property, we use the boolean variable$vSameParent, which is specified in such a way that its value istrue()exactly when the grand-parent of the matched text node is identical to the node contained in$pParent. Finally, we use the fact that when used as a number, a boolean value oftrue()is converted to1and a boolean value offalse()is converted to0.Update: This is a new solution — to the modified by the OP problem:
when this transformation is applied to the provided XML document:
the new wanted result is produced:
Explanation: The same main ideas as with the original problem, with added Muenchian Grouping.