Reputation: 31
I am trying to return part of a string in an XML sheet. I want to keep what is between the brackets in the "Description" field, and move what is outside the brackets to a different field:
The Source XML:
<Log>
<Date>15-Nov-2014</Date>
<TC>14:38:47:13</TC>
<Description>Move this text (but keep this text here)</Description>
</Log>
Desired result is:
<Log>
<Date>15-Nov-2014</Date>
<TC>14:38:47:13</TC>
<Description>but keep this text here</Description>
<MyOtherField>Move this text</MyOtherField>
</Log>
I have tried using the substring-before "(" and 'substring-after ")" functions in line and the output is almost correct - however the snag is that not all the "Description" fields in my source XML sheet have text in brackets, so those are being deleted completely.
Any assistance would be greatly appreciated.
Thank you
Upvotes: 0
Views: 9776
Reputation: 52888
Since you're using XSLT 2.0, you could use xsl:analyze-string
to get the text between the parens...
XML Input
<Log>
<Date>15-Nov-2014</Date>
<TC>14:38:47:13</TC>
<Description>Move this text (but keep this text here)</Description>
</Log>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Description">
<xsl:copy>
<xsl:analyze-string select="." regex="\(([^)]+)\)">
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
<MyOtherField>
<xsl:value-of select="normalize-space(string-join((substring-before(concat(.,'('),'('),
substring-after(.,')')),' '))"/>
</MyOtherField>
</xsl:template>
</xsl:stylesheet>
XML Output
<Log>
<Date>15-Nov-2014</Date>
<TC>14:38:47:13</TC>
<Description>but keep this text here</Description>
<MyOtherField>Move this text</MyOtherField>
</Log>
Here it is integrated into your existing code: http://xsltransform.net/pPzifq1/1
Upvotes: 1
Reputation: 21661
I was able to achieve this using the following template:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Description[contains(text(), '(')]">
<Description>
<xsl:value-of select="substring-before(substring-after(., ' ('), ')')" />
</Description>
<MyOtherField>
<xsl:value-of select="substring-before(., ' (')" />
</MyOtherField>
</xsl:template>
</xsl:transform>
Note that it may not work as expected if you have multiple (
s or )
s. The idea is that you match any Description
tags that contain a (
in them, and then use the substring logic.
http://xsltransform.net/gWvjQfU
Upvotes: 0
Reputation: 117165
Try it this way:
<xsl:template match="Description">
<xsl:copy>
<xsl:value-of select="substring-before(substring-after(., '('), ')')"/>
</xsl:copy>
<MyOtherField>
<xsl:value-of select="substring-before(concat(., '('), '(')"/>
</MyOtherField>
</xsl:template>
Upvotes: 4