1
<Person>
<AdditionalAttributes groupLabel="Profile">
<AdditionalAttribute name="First Name" value="John"/>
<AdditionalAttribute name="Last Name" value="Smith"/>
</AdditionalAttributes>

<AdditionalAttributes groupLabel="Additional">
<AdditionalAttribute name="email" value="John Smith(jsmith)"/>
<AdditionalAttribute name="Created Date" value="2016-04-20T19:50:01Z"/>
</AdditionalAttributes>
</Person>

Can you show me how to use xslt to add @gmail.com to value of element email from John Smith (jsmith) to John Smith(jsmith**@gmail.com**) assuming email value is dynamic

thanks and regards

  • It likely can be done during a copy of the full xml file except a special processing for the email value, but it would be much easier with a regexp search/replace with tools like sed/awk... – B. Go Nov 28 '19 at 00:46
  • 1
    No, it wouldn't. https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – michael.hor257k Nov 28 '19 at 01:08

2 Answers2

0

Try:

XSLT 1.0

<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:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="AdditionalAttribute[@name='email']/@value">
    <xsl:attribute name="value">
        <xsl:value-of select="substring-before(., ')')"/>
        <xsl:text>@gmail.com)</xsl:text>
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

This is assuming there are no closing parentheses other than the last one. Alternatively, you could do:

<xsl:template match="AdditionalAttribute[@name='email']/@value">
    <xsl:attribute name="value">
        <xsl:value-of select="substring(., 1, string-length(.) - 1)"/>
        <xsl:text>@gmail.com)</xsl:text>
    </xsl:attribute>
</xsl:template>

Added:

Can you also show me how to replace "John Smith(jsmith)" with "jsmith@gmail.com" ?

Extract the text in parentheses and append the domain name to it:

<xsl:template match="AdditionalAttribute[@name='email']/@value">
    <xsl:attribute name="value">
        <xsl:value-of select="substring-before(substring-after(., '('), ')')"/>
        <xsl:text>@gmail.com</xsl:text>
    </xsl:attribute>
</xsl:template>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • thank you for quick reply. i ran my java code against your xsl and it gave me this error "SystemId Unknown; Line 7; Column 41; Illegal attribute name: email" And the xml output for email is There's no value – user12448901 Nov 28 '19 at 08:20
  • You can see it working here: https://xsltfiddle.liberty-development.net/6rewNyf – michael.hor257k Nov 28 '19 at 08:24
  • many thanks to your guidance... i found the error , i changed to as you recommended and it works. Can you also show me how to replace "John Smith(jsmith)" with "jsmith@gmail.com" ? – user12448901 Nov 28 '19 at 09:03
  • I don't see why using `email` as the name of the attribute should cause an error (unless you're validating the result against a schema). -- See the addition to my answer for your follow-up question. – michael.hor257k Nov 28 '19 at 09:29
0

I. XSLT 1.0

Similar to the solution of michael.hor257k , but using AVTs -- Attribute-Value Templates.

Thus no need for an <xsl:attribute> operator:

<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()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="AdditionalAttribute[@name='email']">
    <AdditionalAttribute name="email"
        value="{substring-before(@value, '(')
                }({substring-before(
                             substring-after(@value,'('),
                             ')'
                                    )}@gmail.com)">
      <xsl:apply-templates select="@*[not(name()='value')]"/>
    </AdditionalAttribute>
  </xsl:template>
</xsl:stylesheet>

When applied on the provided XML document:

<Person>
    <AdditionalAttributes groupLabel="Profile">
        <AdditionalAttribute name="First Name" value="John"/>
        <AdditionalAttribute name="Last Name" value="Smith"/>
    </AdditionalAttributes>
    <AdditionalAttributes groupLabel="Additional">
        <AdditionalAttribute name="email" value="John Smith(jsmith)"/>
        <AdditionalAttribute name="Created Date" value="2016-04-20T19:50:01Z"/>
    </AdditionalAttributes>
</Person>

the wanted, correct result is produced:

<Person>
   <AdditionalAttributes groupLabel="Profile">
      <AdditionalAttribute name="First Name" value="John"/>
      <AdditionalAttribute name="Last Name" value="Smith"/>
   </AdditionalAttributes>
   <AdditionalAttributes groupLabel="Additional">
      <AdditionalAttribute name="email" value="John Smith(jsmith@gmail.com)"/>
      <AdditionalAttribute name="Created Date" value="2016-04-20T19:50:01Z"/>
   </AdditionalAttributes>
</Person>

II. XSLT 2.0

This transformation uses AVT again and the XPath 2.0 replace() function:

<xsl:stylesheet version="2.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()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="AdditionalAttribute[@name='email']">
    <AdditionalAttribute name="email"
        value="{replace(@value, '\)', '@gmail.com)')}">
      <xsl:apply-templates select="@*[not(name()='value')]"/>
    </AdditionalAttribute>
  </xsl:template>
</xsl:stylesheet>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • i'm using xslt 1.0, and all your suggestion works. I'm trying to do this I want to replace all value of attribute code="Hello" to code="Chao". this code below does it, but it also remove value of code="Bye" Chao – user12448901 Dec 02 '19 at 09:46
  • @user12448901 Glad it works, Please, *accept* the answer and ask a new question with the new problem. Notify me via a comment when you have posted the new question. – Dimitre Novatchev Dec 02 '19 at 16:22
  • thanks Dimitre for your help. here is my other question https://stackoverflow.com/questions/59143630/xslt-replaces-attributes-value-correctly-but-also-empties-other-attributes – user12448901 Dec 02 '19 at 17:09
  • @user12448901, There is already a good answer by michael.hor257k – Dimitre Novatchev Dec 02 '19 at 17:20