Removing the last characters in an XSLT string - image

In my CMS it is possible to create a new article, and choose an image to be shown on that article. When an image is chosen, a thumbnail of the image will automatically be created as well.
If the uploaded image is called image.jpg, then the corresponding thumbnail will automatically be named image_thumbnail.jpg.
I would now like to use the thumbnail image, everywhere on the website where the article is mentioned, except in the article itself (where the original big image should be shown).
But how can I do that?
I imagine if I could get the original name of the image, and then split it up before the suffix (.jpg, .png, .jpeg etc.) and hardcode _thumbnail after the name, then that would be sufficient.
In other words, I want to take the complete filename, and cut it into two parts, so that I can insert the string _thumbnail between the two parts.
Maybe that would work, but what if an image called image.2horses.jpg (a file with more than one dot in the filename) is uploaded? A naive cut before the '.' wouldn't work here.
Is there a way to get around this? Perhaps by cutting the filename up before the last 4 (.jpg, .png) or 5 (.jpeg) characters?

Off the top of my head:
<xsl:template name="substring-before-last">
<xsl:param name="string1" select="''" />
<xsl:param name="string2" select="''" />
<xsl:if test="$string1 != '' and $string2 != ''">
<xsl:variable name="head" select="substring-before($string1, $string2)" />
<xsl:variable name="tail" select="substring-after($string1, $string2)" />
<xsl:value-of select="$head" />
<xsl:if test="contains($tail, $string2)">
<xsl:value-of select="$string2" />
<xsl:call-template name="substring-before-last">
<xsl:with-param name="string1" select="$tail" />
<xsl:with-param name="string2" select="$string2" />
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
Called as:
<xsl:template match="/">
<xsl:variable name="filename" select="'image.2horses.jpg'" />
<xsl:variable name="basename">
<xsl:call-template name="substring-before-last">
<xsl:with-param name="string1" select="$filename" />
<xsl:with-param name="string2" select="'.'" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$basename" />
</xsl:template>
Yields:
image.2horses

Given the image's filename in $filename,
If you can assume that all images will end in ".jpg" and won't have ".jpg" elsewhere in the filename, then this should work:
<img src="{substring-before($filename, '.jpg')}_thumbnail.jpg" ... />
If you don't know the image type (like, you want to handle gif and png as well), or if you think the extension may occur multiple times in the filename ("image.jpg.jpg"), then you will want a template to help you:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image.jpg'"/>
</xsl:call-template>
</p>
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image.09.07.11.jpg'"/>
</xsl:call-template>
</p>
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image.gif'"/>
</xsl:call-template>
</p>
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image with spaces.jpg'"/>
</xsl:call-template>
</p>
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image with irregular spaces.jpg'"/>
</xsl:call-template>
</p>
<p>
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="'image.jpg.again.jpg'"/>
</xsl:call-template>
</p>
</xsl:template>
<xsl:template name="image_thumbnail">
<xsl:param name="filename"/>
<xsl:choose>
<xsl:when test="contains($filename, '.')">
<xsl:variable name="before" select="substring-before($filename, '.')"/>
<xsl:variable name="after" select="substring-after($filename, '.')"/>
<xsl:choose>
<xsl:when test="contains($after, '.')">
<xsl:variable name="recursive">
<xsl:call-template name="image_thumbnail">
<xsl:with-param name="filename" select="$after"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($before, '.', $recursive)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($before, '_thumbnail.', $after)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$filename"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

A general solution involving only standard XSLT is somewhat hard since you have to search the string from the end. You can split your filename usings two functions, substring-before-last and substring-after-last. Unfortunately, these functions are not part of XSLT. You can Google and try to find implementations. Assuming you have these two functions implemented as XSLT templates you can then use the following template to generate thumbnail names:
<xsl:template name="thumbnail-name">
<xsl:param name="file-name"/>
<xsl:call-template name="substring-before-last">
<xsl:with-param name="text" select="$file-name"/>
<xsl:with-param name="chars" select="'.'"/>
</xsl:call-template>
<xsl:text>_thumbnail.</xsl:text>
<xsl:call-template name="substring-after-last">
<xsl:with-param name="text" select="$file-name"/>
<xsl:with-param name="chars" select="'.'"/>
</xsl:call-template>
</xsl:template>
You can use the template like this (assuming the variable $file-name contains the name of the image):
<img>
<xsl:attribute name="src">
<xsl:call-template name="thumbnail-name">
<xsl:with-param name="file-name" select="$file-name"/>
</xsl:call-template>
</xsl:attribute>
</img>

Have a look at the XPath functions overview at W3Schools, specifically the substring-before method.

I believe XPath functions operating on string might help you. I would try with some simple replace or translate.

XSLT 2 solution using regexp:
replace($filename, '(\.[^\.]*)$', concat('_thumbnail', '$1'))
Original answer (also XSLT 2):
This removes all after the last separator (including the separator). So below the $separatorRegexp could be '\.jpg' or just '\.' and the $separator '.jpg' or '.' in the other case.
string-join(reverse(remove(reverse(tokenize($filename, $separatorRegexp)),1)),$separator)
Eventually the '_thumbnail.jpg' can be appended with concat.

Related

How to match the case and apply templates

I've the below XML line of code.
<title><page>651</page>CHAPTER 13 This is <content-style font-style="italic">This goes in content-style</content-style> The title</title>
Here i'm trying to do the below.
Get the number after CHAPTER and concat it with Chapter, i'm able to do it with the below code.
<xsl:value-of select="concat('Chapter ', substring-before(substring-after(child::title,' '),' ')"/>
ignore the page in the title, and i use the below template match and able to do it.
<xsl:template match="title/page"/>
If there is just plain data, i'm using the below to get it.
<xsl:value of select ="substring-after(substring-after(./title,' '),' ')">
But the problem came in the above type, here i need to apply templates on substring-after(substring-after(.,' '),' ') and unfortunately this is not working.
I have the below XSLT
<xsl:template match ="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="content-style">
<xsl:variable name="fontStyle">
<xsl:value-of select="concat('font-style-',#font-style)"/>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:template>
expected O/P
<div class="chapter-title">
<span class="chapter-num">Chapter 13</span><br /><br /> This is <span class="font-style-italic">This goes in content-style</span> the title</span></div>
Can you please let me know how can i do this.
Thanks
Your expected output has an unmatched span end tag.
Ignoring that, I would do something like:
<xsl:template match ="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="content-style">
<span class="font-style-{#font-style}">
<xsl:value-of select="."/>
</span>
</xsl:template>
<xsl:template match="title/text()">
<xsl:analyze-string select="." regex="Chapter [0-9]+">
<xsl:matching-substring>
<span class="chapter-num">
<xsl:value-of select="."/>
</span><br/>>br/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:-nonmatching-substring>
</xsl:analyze-string>
</xsl:template>

Breaking a lengthy row into multiple rows using Xpath expression in Altova Stylevision's Autocalc functionality

I have a XML row which has a lengthy sentence for instance:
<ROW>4.)Whatever universe a professor believes in must at any rate be a universe that lends itself to lengthy discourse. A universe definable in two sentences is something for which the professorial intellect has no use. No faith in anything of that cheap kind!
I need to break the sentence into smaller sentences and display them in multiple lines in Altova Stylevision.
Iam using Autocalc to display the contents in row dynamically. Is there any Xpath expression which I can use to split the row into multiple rows based on the number of words or number of characters in each line.So that I can display the row as:
Whatever universe a professor believes in must at any rate
be a universe that lends itself to lengthy discourse.
and so on.
It seems you are trying to break your string input into multiple pieces (word/String length). I have created a sample for you to make it easy. Please go through and check if it can help you:
input xml
<?xml version="1.0" encoding="UTF-8"?>
<ROW>4.)Whatever universe a professor believes in must at any rate be a universe that lends itself to lengthy discourse. A universe definable in two sentences is something for which the professorial intellect has no use. No faith in anything of that cheap kind!11</ROW>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="ROW">
<output>
<xsl:variable name="Length" select="string-length(.)"/>
<xsl:variable name="Words" select="count(tokenize(.,'\s'))"/>
<xsl:variable name="ByLength" select="50"/>
<xsl:variable name="ByWord" select="5"/>
<!-- To get ouput by words -->
<xsl:if test="$ByWord">
<xsl:variable name="Result">
<xsl:call-template name="GetBreakingWords">
<xsl:with-param name="Value" select="."/>
<xsl:with-param name="ByWord" select="$ByWord"/>
<xsl:with-param name="Words" select="$Words"/>
</xsl:call-template>
</xsl:variable>
<p>By word example</p>
<xsl:for-each select="$Result/row">
<xsl:sort select="#id" data-type="number"/>
<!--<row><xsl:value-of select="."/></row>-->
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
<!-- To get ouput by string length -->
<xsl:if test="$ByLength">
<xsl:variable name="Result">
<xsl:call-template name="GetBreakingStrings">
<xsl:with-param name="Value" select="."/>
<xsl:with-param name="ByLength" select="$ByLength"/>
<xsl:with-param name="Length" select="$Length"/>
</xsl:call-template>
</xsl:variable>
<p>By String example</p>
<xsl:for-each select="$Result/row">
<xsl:sort select="#id" data-type="number"/>
<!--<row><xsl:value-of select="."/></row>-->
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
</output>
</xsl:template>
<xsl:template name="GetBreakingWords">
<xsl:param name="ByWord"/>
<xsl:param name="Value"/>
<xsl:param name="Words"/>
<xsl:param name="counter" select="1"/>
<xsl:choose>
<xsl:when test="($Words gt $ByWord)">
<xsl:variable name="CurrentRow" select="normalize-space(string-join(for $x in tokenize($Value, '\s')[position() ge 1 and position() le $ByWord] return $x, ' '))"/>
<xsl:call-template name="GetBreakingWords">
<xsl:with-param name="ByWord" select="$ByWord"/>
<xsl:with-param name="Words" select="count(tokenize(substring-after($Value, $CurrentRow),'\s'))"/>
<xsl:with-param name="Value" select="substring-after($Value, $CurrentRow)"/>
<xsl:with-param name="counter" select="sum($counter + 1)"></xsl:with-param>
</xsl:call-template>
<row id="{$counter}"><xsl:value-of select="$CurrentRow"/></row>
</xsl:when>
<xsl:when test="not($Words gt $ByWord) and $Value">
<row id="{$counter}"><xsl:value-of select="$Value"/></row>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="GetBreakingStrings">
<xsl:param name="ByLength"/>
<xsl:param name="Value"/>
<xsl:param name="Length"/>
<xsl:param name="counter" select="1"/>
<xsl:choose>
<xsl:when test="($Length gt $ByLength)">
<xsl:variable name="CurrentRow" select="normalize-space(string-join(substring($Value,0,$ByLength),' '))"/>
<xsl:call-template name="GetBreakingStrings">
<xsl:with-param name="ByLength" select="$ByLength"/>
<xsl:with-param name="Length" select="string-length(substring-after($Value, $CurrentRow))"/>
<xsl:with-param name="Value" select="substring-after($Value, $CurrentRow)"/>
<xsl:with-param name="counter" select="sum($counter + 1)"></xsl:with-param>
</xsl:call-template>
<row id="{$counter}"><xsl:value-of select="$CurrentRow"/></row>
</xsl:when>
<xsl:when test="not($Length gt $ByLength) and $Value">
<row id="{$counter}"><xsl:value-of select="$Value"/></row>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
output:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<p>By word example</p>
<row id="1">4.)Whatever universe a professor believes</row>
<row id="2">in must at any</row>
<row id="3">rate be a universe</row>
<row id="4">that lends itself to</row>
<row id="5">lengthy discourse. A universe</row>
<row id="6">definable in two sentences</row>
<row id="7">is something for which</row>
<row id="8">the professorial intellect has</row>
<row id="9">no use. No faith</row>
<row id="10">in anything of that</row>
<row id="11"> cheap kind!11</row>
<p>By String example</p>
<row id="1">4.)Whatever universe a professor believes in must</row>
<row id="2">at any rate be a universe that lends itself to l</row>
<row id="3">engthy discourse. A universe definable in two sen</row>
<row id="4">tences is something for which the professorial in</row>
<row id="5">tellect has no use. No faith in anything of that</row>
<row id="6"> cheap kind!11</row>
</output>

Get full XPath from partial

I am using selenium with perl and have label on page, to access this label i have following xpath: //*[text()='some here'] , the problem that a need to get full xpath of this element, like /html/body/table/tr/..../any other/and other/ , is there is any selenium method or perl function ? looking for perl solution or any other working things.
thanks
looking for perl solution or any other
working things
This XPath 2.0 expression:
string-join(for $node in ancestor-or-self::node()
return concat(('#')[$node/self::attribute()],
$node/name(),
(concat('[',
count($node/preceding-sibling::node()
[name()=$node/name()]) + 1,
']'))[$node/../node()
[name()=$node/name()][2]]),
'/')
Edit: Shorter expression.
This XSLT 1.0 transformation produces an XPath expression for every node contained in the $pNode parameter:
<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:template match="node()|#*">
<path>
<xsl:call-template name="buildPath"/>
</path>
<xsl:apply-templates select="node()|#*"/>
</xsl:template>
<xsl:template name="buildPath">
<xsl:variable name="pNode" select="."/>
<xsl:variable name="theResult">
<xsl:for-each select="$pNode">
<xsl:variable name="theNode" select="."/>
<xsl:for-each select=
"$theNode
|
$theNode/ancestor-or-self::node()[..]">
<xsl:element name="slash">/</xsl:element>
<xsl:choose>
<xsl:when test="self::*">
<xsl:element name="nodeName">
<xsl:value-of select="name()"/>
<xsl:variable name="thisPosition" select=
"count(preceding-sibling::*
[name(current())
=
name()])"/>
<xsl:variable name="numFollowing" select=
"count(following-sibling::
*[name(current())
=
name()])"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:otherwise> <!-- This node is not an element -->
<xsl:choose>
<xsl:when test="count(. | ../#*) = count(../#*)">
<!-- Attribute -->
<xsl:element name="nodeName">
<xsl:value-of select="concat('#',name())"/>
</xsl:element>
</xsl:when>
<xsl:when test="self::text()"> <!-- Text -->
<xsl:element name="nodeName">
<xsl:value-of select="'text()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::text())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::text())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:when test="self::processing-instruction()">
<!-- Processing Instruction -->
<xsl:element name="nodeName">
<xsl:value-of select="'processing-instruction()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::processing-instruction())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::processing-instruction())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:when test="self::comment()"> <!-- Comment -->
<xsl:element name="nodeName">
<xsl:value-of select="'comment()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::comment())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::comment())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<!-- Namespace: -->
<xsl:when test=
"count(. | ../namespace::*)
=
count(../namespace::*)">
<xsl:variable name="apos">'</xsl:variable>
<xsl:element name="nodeName">
<xsl:value-of select="concat('namespace::*',
'[local-name() = ', $apos, local-name(), $apos, ']')"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!-- <xsl:text>
</xsl:text> -->
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$theResult"/>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<div id="entry-1" class="item-asset asset hentry">
<div class="asset-header">
<h2 class="asset-name entry-title">
<a rel="bookmark" href="http://blahblah.com/paper-scissors">Paper Scissors</a>
</h2>
</div>
<div class="asset-content entry-content">
<div class="asset-body">
<p>Paper and scissors</p>
</div>
</div>
</div>
the result is a list of the XPath expressions for every node in the document:
<path>/div</path>
<path>/div/#id</path>
<path>/div/#class</path>
<path>/div/div[1]</path>
<path>/div/div[1]/#class</path>
<path>/div/div[1]/h2</path>
<path>/div/div[1]/h2/#class</path>
<path>/div/div[1]/h2/a</path>
<path>/div/div[1]/h2/a/#rel</path>
<path>/div/div[1]/h2/a/#href</path>
<path>/div/div[1]/h2/a/text()</path>
<path>/div/div[2]</path>
<path>/div/div[2]/#class</path>
<path>/div/div[2]/div</path>
<path>/div/div[2]/div/#class</path>
<path>/div/div[2]/div/p</path>
<path>/div/div[2]/div/p/text()</path>

is there a way to emulate correctly replace function on XPATH 1?

I have this function which tries to replace dots and/or - with _
I'm limited to use xpath 1 so replace function is NOT an option. The template works not to much fine because if I use something like this:
FOO-BAR.THING-MADRID.html
it gives me out on screen this thing:
FOO-BAR.THING-MADRID.html
the middle dot is not replaced.
Someone could help me?
<xsl:template name="replaceDots">
<xsl:param name="outputString"/>
<xsl:variable name="target">.</xsl:variable>
<xsl:variable name="source">-</xsl:variable>
<xsl:variable name="replacement">_</xsl:variable>
<xsl:choose>
<xsl:when test="contains($outputString,$source)">
<xsl:value-of select="concat(substring-before($outputString,$source),$replacement)" disable-output-escaping="yes"/>
<xsl:call-template name="replaceDots">
<xsl:with-param name="outputString" select="substring-after($outputString,$source)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($outputString,$target)">
<xsl:value-of select="concat(substring-before($outputString,$target),$replacement)" disable-output-escaping="yes"/>
<xsl:call-template name="replaceDots">
<xsl:with-param name="outputString" select="substring-after($outputString,$target)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$outputString" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
To replace all dots or dashes with underscores, you do not need an <xsl:template>. You can use:
<xsl:value-of select="translate(., '-.', '__')" />
If you want to keep the ".html", you can extend this like so:
<xsl:value-of select="
concat(
translate(substring-before(., '.html'), '-.', '__'),
'.hmtl'
)
" />
For a generic "string replace" template in XSLT, look at this question, for example.

Modify an XML node using [MS] XSLT Script

I would like to select a node and modify its attributes and child-nodes using an
xsl:script function. In addition, templates matching child-nodes of that node should
STILL perform their job (after script is done processing the node).
Can it be done using XSLT?
Can you please provide an example / skeleton for such a transformation?
Yes, it can be done. I don't seem to see what the problem is because the XML (or whatever output) of an XSL script is buffered independently from its input.
This is illustrated in the following example whereby a simple XSL script copies an input XML document mostly as-is, changing a few things:
the root element name and attribute
flattening by removing the element from the hierarchy
dropping the results/date element
rename the item's 'source' attribute 'origin'
change the item's 'level' attribute value
rename the FirstName and LastName elements of the item elements
Sample input
<?xml version="1.0" encoding="ISO-8859-1"?>
<MyRoot version="1.2">
<results>
<info>Alpha Bravo</info>
<author>Employee No 321</author>
<date/>
<item source="www" level="6" cost="33">
<FirstName>Jack</FirstName>
<LastName>Frost</LastName>
<Date>1998-10-30</Date>
<Organization>Lemon growers association</Organization>
</item>
<item source="db-11" level="1" cost="65" qry="routine 21">
<FirstName>Mike</FirstName>
<LastName>Black</LastName>
<Date>2006-10-30</Date>
<Organization>Ford Motor Company</Organization>
</item>
</results>
</MyRoot>
Output produced
<?xml version="1.0" encoding="utf-16"?>
<MyNewRoot version="0.1">
<author>Employee No 321</author>
<info>Alpha Bravo</info>
<item cost="33" origin="www" level="77">
<GivenName>Jack</GivenName>
<FamilyName>Frost</FamilyName>
<Date>1998-10-30</Date>
<Organization>Lemon growers association</Organization>
</item>
<item cost="65" qry="routine 21" origin="db-11" level="77">
<GivenName>Mike</GivenName>
<FamilyName>Black</FamilyName>
<Date>2006-10-30</Date>
<Organization>Ford Motor Company</Organization>
</item>
</MyNewRoot>
XSL script
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#default">
<xsl:template match="MyRoot">
<xsl:call-template name="MainTemplate">
</xsl:call-template>
</xsl:template>
<xsl:template name="MainTemplate">
<MyNewRoot version="0.1">
<xsl:copy-of select="results/author" />
<xsl:copy-of select="results/info" />
<xsl:for-each select="results/item">
<xsl:call-template name="FixItemElement"/>
</xsl:for-each>
</MyNewRoot>
</xsl:template>
<xsl:template name="FixItemElement">
<xsl:copy>
<xsl:copy-of select="#*[not(name()='source' or name()='level')]" />
<xsl:attribute name="origin">
<xsl:value-of select="#source"/>
</xsl:attribute>
<xsl:attribute name="level">
<xsl:value-of select="77"/>
</xsl:attribute>
<xsl:for-each select="descendant::*">
<xsl:choose>
<xsl:when test="local-name(.) = 'FirstName'">
<GivenName>
<xsl:value-of select="."/>
</GivenName>
</xsl:when>
<xsl:when test="local-name(.) = 'LastName'">
<FamilyName>
<xsl:value-of select="."/>
</FamilyName>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>

Resources