Given the following xml fragment:
<Problems>
<Problem>
<File>file1</File>
<Description>desc1</Description>
</Problem>
<Problem>
<File>file1</File>
<Description>desc2</Description>
</Problem>
<Problem>
<File>file2</File>
<Description>desc1</Description>
</Problem>
</Problems>
I need to produce something like
<html>
<body>
<h1>file1</h1>
<p>des1</p>
<p>desc2</p>
<h1>file2</h1>
<p>des1</p>
</body>
</html>
I tried using a key, like
<xsl:key name="files" match="Problem" use="File"/>
but I don't really understand how to take it to the next step, or if that's even the right approach.
The objects in some collection are described as "distinct" if each is different from the others. So an array with distinct elements is one where no two elements are the same.
Answer: In math, the term distinct number is used to refer to a number in a set that is not equal to another number. For example, the set of numbers {1, 2} contains the two distinct numbers 1 and 2, which can be proven by evaluating different traits of each number.
Cardinality of sets The number of elements in a particular set is a property known as cardinality; informally, this is the size of a set. In the above examples, the cardinality of the set A is 4, while the cardinality of set B and set C are both 3.
If G is a finite group, every g ∈ G has finite order. The proof is as follows. Since the set of powers {ga : a ∈ Z} is a subset of G and the exponents a run over all integers, an infinite set, there must be a repetition: ga = gb for some a<b in Z. Then gb−a = e, so g has finite order.
This solution is a little bit simpler, more efficient and at the same time more general than the one presented by Richard:
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- -->
<xsl:key name="kFileByVal" match="File"
use="." />
<!-- -->
<xsl:key name="kDescByFile" match="Description"
use="../File"/>
<!-- -->
<xsl:template match="/*">
<html>
<body>
<xsl:for-each select=
"*/File[generate-id()
=
generate-id(key('kFileByVal',.)[1])]">
<h1><xsl:value-of select="."/></h1>
<xsl:for-each select="key('kDescByFile', .)">
<p><xsl:value-of select="."/></p>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
when applied to the provided XML document:
<Problems>
<Problem>
<File>file1</File>
<Description>desc1</Description>
</Problem>
<Problem>
<File>file1</File>
<Description>desc2</Description>
</Problem>
<Problem>
<File>file2</File>
<Description>desc1</Description>
</Problem>
</Problems>
Produces the wanted result:
<html>
<body>
<h1>file1</h1>
<p>desc1</p>
<p>desc2</p>
<h1>file2</h1>
<p>desc1</p>
</body>
</html>
Do note the simple match pattern of the first <xsl:key>
and how, using a second <xsl:key>
, we locate all "Description
" elements that are siblings of a "File
" element that has a given value.
We could have used more templates instead of <xsl:for-each>
pull-processing, however this is a quite simple case and the solution really benefits from shorter, more compact and more readable code.
Also note, that in XSLT 2.0 one will typically use the <xsl:for-each-group>
instruction instead of the Muenchian method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With