Reputation: 511
I need xsl template that for specified ‘element_type’ under specified ‘path’ with attribute ‘name’ value matched to ‘old_value’ will replace ‘old_value’ with ‘new_value’
I created xsl template with proper handling for ‘element_type’, ‘old_value’, ‘new_value’ parameters. I stacked with handling ‘path’ parameter. Below is input xml
<?xml version="1.0" encoding="utf-8"?>
<storage name="hdd1">
<folder name="root">
<folder name="sub1">
<folder name="sub1-sub">
<file name="temp-docs"/>
<folder name="temp-docs"/>
<folder name="temp-pictures"/>
</folder>
</folder>
<folder name="sub2">
<folder name="temp-docs">
<folder name="inner-temp-bar"/>
</folder>
<folder name="temp-pictures"/>
</folder>
</folder>
<folder name="temp-docs"/>
<folder name="temp-pictures"/>
</storage>
The next is designed XSL:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="element_type"/>
<xsl:param name="path"/>
<xsl:param name="old_value"/>
<xsl:param name="new_value"/>
<xsl:template match="/ | * | @*">
<xsl:copy>
<xsl:apply-templates select="* | @* | text()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:choose>
<xsl:when test="contains(., $old_value)
and local-name() = 'name'
and name(..) = $element_type
and ancestor::*[2]/@name = $path">
<xsl:attribute name="name">
<xsl:value-of select="substring-before(., $old_value)"/>
<xsl:value-of select="$new_value"/>
<xsl:value-of select="substring-after(., $old_value)"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="* | @* | text()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
For input parameters:
'element_type' = 'folder'
'old_value' = 'temp-'
'new_value' = ''
'path'= 'sub2'
The above XSL application to above XML result is (renamed all 'folder' element, but not 'folder' element with name="inner-temp-bar):
<?xml version="1.0" encoding="UTF-8"?>
<storage name="hdd1">
<folder name="root">
<folder name="sub1">
<folder name="sub1-sub">
<file name="temp-docs"/>
<folder name="temp-docs"/>
<folder name="temp-pictures"/>
</folder>
</folder>
<folder name="sub2">
<folder name="docs">
<folder name="inner-temp-docs"/>
</folder>
<folder name="pictures"/>
</folder>
</folder>
<folder name="temp-docs"/>
<folder name="temp-pictures"/>
</storage>
The goal is rename all folders and subfolders under specified path, e.g:
- 'path' = 'root/sub2' will rename all 'folder' elements inside 'sub2' element;
- 'path' = 'root' will rename all 'folder' elements inside 'sub1' and 'sub2' element.
How I need to handle 'path' parameter to achieve above goal?
Upvotes: 0
Views: 44
Reputation: 167716
Here is an XSLT 2.0 stylesheet:
<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:param name="element_type" select="'folder'"/>
<xsl:param name="path" select="'root/sub2'"/>
<xsl:param name="old_value" select="'temp-'"/>
<xsl:param name="new_value" select="''"/>
<xsl:param name="path-tokens" as="xs:string*" select="tokenize($path, '/')"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[string-join(ancestor-or-self::*[position() le count($path-tokens)]/@name, '/') eq $path]//*[local-name() eq $element_type]/@name[contains(., $old_value)]">
<xsl:attribute name="{name()}" select="replace(., $old_value, $new_value)"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1