Reputation: 815
I have an XML document containing lists of people structured like this:
<listPerson>
<person xml:id="John_de_Foo">
<persName>
<forename>John</forename>
<nameLink>de</nameLink>
<surname>Foo</surname>
<role>snake charmer</role>
</persName>
</person>
<person xml:id="John_de_Foo_jr">
<persName>
<forename>John</forename>
<nameLink>de</nameLink>
<surname>Foo</surname>
<genname>junior</genname>
</persName>
</person>
<person xml:id="M_de_Foo">
<persName>
<forename>M</forename>
<nameLink>de</nameLink>
<surname>Foo</surname>
</persName>
</person>
[...]
</listPerson>
I am extracting only certain fields and concatenating them with tokenize()
to create a new element <fullname>
using XSL 3.0 (where $doc = current document):
<xsl:template match="listPerson/person">
<fullname>
<xsl:value-of select="$p/persName/name, $p/persName/forename, $p/persName/nameLink, $p/persName/surname, $p/persName/addName, $p/persName/genName" separator=" "/>
</fullname>
<xsl:template/>
Outputs:
<fullname>John de Foo</fullname>
<fullname>John de Foo junior</fullname>
<fullname>M de Foo</fullname>
But, I'd like to treat the element <forename>
with a specific test. If the forename/@text
is a single initial, add .
. The new result would output:
<fullname>John de Foo</fullname>
<fullname>John de Foo junior</fullname>
<fullname>M. de Foo</fullname>
Also, the <forename>
element may not exist, in which case it should bypass the test.
I can do this by changing the tokenize()
to a series of <xsl:if>
statements, but I'd rather try to solve it within XPATH if possible.
Thanks in advance
Upvotes: 2
Views: 327
Reputation: 167401
If you want the forename
to be suffixed with a full stop if it has a string length on one you can in XPath 3.1 use forename!(if (string-length() eq 1) then . || '.' else .)
e.g. in a full template:
<xsl:template match="persName">
<fullname>
<xsl:value-of select="forename!(if (string-length() eq 1) then . || '.' else .), nameLink, surname, genname" separator=" "/>
</fullname>
</xsl:template>
https://xsltfiddle.liberty-development.net/bdxtq5
Will of course work the same with a different expression e.g. $p/persName/forename!(if (string-length() eq 1) then . || '.' else .)
Upvotes: 3
Reputation: 29022
In XPath 2.0 there is an if-then-else expression which you can use directly in the xsl:value-of
like this:
<xsl:value-of select="$p/persName/name, if (string-length($p/persName/forename) = 1) then concat($p/persName/forename,'.') else $p/persName/forename , $p/persName/nameLink, $p/persName/surname, $p/persName/addName, $p/persName/genName" separator=" " />
An alternative is using the if-then-else in the concat(...)
function:
<xsl:value-of select="$p/persName/name, concat($p/persName/forename, if (string-length($p/persName/forename) = 1) then '.' else ''), $p/persName/nameLink, $p/persName/surname, $p/persName/addName, $p/persName/genName" separator=" " />
Upvotes: 5