I am trying to use apply-templates for elements encapsulated within parent element but has different element name. In my example I want to apply it to /Author/Name/
elements and choose either of one whichever has a value. This task is continuation of another question I have asked.
I am using the following XML
<?xml version="1.0" encoding="UTF-8"?>
<Author>
<Info>
<Name>
<FirstName>#3 bb***</FirstName>
<LastName>test</LastName>
</Name>
<Input>
<Item>##### 3 ??***</Item>
</Input>
</Info>
<Custom>Test</Custom>
</Author>
I am applying the following XSLT 1.0 using java. In above example I want template applied to firstName and lastName but show value in firstName since it is the first with a value.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="allowed-start-chars">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="allowed-follow-chars">0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ?abcdefghijklmnopqrstuvwxyz-'.,/@&()! </xsl:variable>
<xsl:template match="/">
<html>
<body>
<!-- Not sure how to use `xsl:choose` just added to show my intentions-->
<xsl:choose>
<xsl:when test="..">
<div>
<xsl:apply-templates select="Author/Name/FirstName"/>
</div>
</xsl:when>
</xsl:choose>
</body>
</html>
</xsl:template>
<!--used pipe to apply for two different elements but it does not work-->
<xsl:template match="FirstName|LastName">
<!-- find the first character eligible to be starting character -->
<xsl:variable name="start-chars" select="translate(., translate(., $allowed-start-chars, ''), '')"/>
<xsl:variable name="start-char" select="substring($start-chars, 1, 1)"/>
<!-- get text after the chosen starting character -->
<xsl:variable name="tail" select="substring-after(., $start-char)"/>
<!-- remove unwanted characters from tail -->
<xsl:variable name="fo" select="translate($tail, translate($tail, $allowed-follow-chars, ''), '')"/> <xsl:choose>
<!--only show if character remain after removing bad ones, and not empty-->
<xsl:when test="string-length($start-char) > 0 and normalize-space(concat($start-char, $fo))">
<xsl:value-of select="normalize-space(concat($start-char, $fo))"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The Java code is Stylizer class from Oracle tuorial page example, please refer the link for full code. I am running command-line sending xml and xslt files.
File stylesheet = new File(argv[0]);
File datafile = new File(argv[1]);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(datafile);
// Use a Transformer for output
TransformerFactory tFactory = TransformerFactory.newInstance();
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = tFactory.newTransformer(stylesource);
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
I would appreciate again help on this one. As I am learning XSLT and I am also not sure what performance issue using approach
CodePudding user response:
From the context of:
<xsl:template match="/">
you can do:
<xsl:apply-templates select="(Author/Info/Name/FirstName | Author/Info/Name/LastName)[text()][1]"/>
to select the first element of the two that has a child text node. If there are only FirstName
and LastName
, you can shorten this to:
<xsl:apply-templates select="Author/Info/Name/*[text()][1]"/>
Note that your attempt:
<xsl:apply-templates select="Author/Name/FirstName"/>
cannot work because Name
is not a child of Author
.