I am a XSLT newbie, would like to get regex to match this pattern.
String1-number-String2
I need to capture the substring before the second hyphen.
You can use for example replace function:
<!-- this will return "number" -->
<xsl:value-of select="replace('String1-number-String2', '(.*)-(.*)-(.*)', '$2')" />
<!-- this will return "String1-number" -->
<xsl:value-of select="replace('String1-number-String2', '(.*)-(.*)-(.*)', '$1-$2')" />
<xsl:value-of select="replace('String1-number-String2', '(.*-.*)-(.*)', '$1')" />
You could use replace() with the regex ^([^-]+-[^-]+).*.
Example...
XML
<test>String1-number-String2</test>
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="/*">
<results>
<xsl:value-of select="replace(.,'^([^-]+-[^-]+).*','$1')"/>
</results>
</xsl:template>
</xsl:stylesheet>
Output
<results>String1-number</results>
Here is a XPath 1.0/2.0 string function solution (not regex) that will work for the 'String1-number-String2' example:
<xsl:value-of select="substring-before(substring-after('String1-number-String2','-'), '-')"/>
---edit---
I seem to have misunderstood. That string function will return 'number', not 'String1-number'.
Here is an XPath 2.0 solution that will return 'String1-number':
<xsl:variable name="substrings" select="tokenize('String1-number-String2','-')"/>
<xsl:value-of select="concat($substrings[1], '-', $substrings[2])"/>
Related
A XSLT with a xsl:text containing a single (or multiple) whitespace(s) is not printing the whitespace(s) in MarkLogic 9.0-9. See the following example:
xquery version "1.0-ml";
let $doc :=
<doc>
<foo>foo</foo>
<bar>bar</bar>
</doc>
let $xsl :=
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text" omit-xml-declaration="yes" indent="no" />
<xsl:template match="doc">
<xsl:value-of select="foo"/>
<xsl:text> </xsl:text>
<xsl:value-of select="bar"/>
</xsl:template>
</xsl:stylesheet>
return xdmp:xslt-eval($xsl, $doc) = "foo bar"
This returns false. The result is "foobar". I actually expected "foo bar".
I also tried with <xsl:text xml:space="preserve"> </xsl:text> but this does not work either.
As a workaround I currently use <xsl:value-of select="' '"/> which works fine but I am wondering if this is a bug? Using the same transformation and document in Saxon prints the whitespaces.
For standard XQuery you should get what you want with
declare boundary-space preserve;
in the query prolog, see https://www.w3.org/TR/xquery-31/#id-boundary-space-decls and https://www.w3.org/TR/xquery-31/#id-whitespace.
Example is https://xqueryfiddle.liberty-development.net/eiQZDbq/4 doing
declare boundary-space preserve;
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method 'text';
let $doc :=
<doc>
<foo>foo</foo>
<bar>bar</bar>
</doc>
let $xsl :=
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text" omit-xml-declaration="yes" indent="no" />
<xsl:template match="doc">
<xsl:value-of select="foo"/>
<xsl:text> </xsl:text>
<xsl:value-of select="bar"/>
</xsl:template>
</xsl:stylesheet>
return transform(map { 'source-node' : $doc, 'stylesheet-node' : $xsl })?output
returning foo bar while https://xqueryfiddle.liberty-development.net/eiQZDbq/2 without that declaration returns foobar.
I have not checked whether Marklogic supports that declaration or some proprietary similar way to change parsing treatment of whitespace in element constructors.
I am trying to conditional check on the input xml file and place the value.
input xml:
<workorder>
<newwo>1</newwo>
</workorder>
If newwo is 1, then I have to set in my output as "NEW" else "OLD"
Expected output is:
newwo: "NEW"
my xslt is:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:template match="/">
<xsl:apply-templates select="NEWWO" />
</xsl:template>
<xsl:template match="/NEWWO">
<xsl:text>{
newwo:"
</xsl:text>
<xsl:choose>
<xsl:when test="NEWWO != '0'">NEW</xsl:when>
<xsl:otherwise>OLD</xsl:otherwise>
</xsl:choose>
<xsl:text>"
}</xsl:text>
</xsl:template>
Please help me. Thanks in advance!
I see a number of reasons you aren't getting output.
The xpaths are case sensitive. NEWWO is not going to match newwo.
You match / and then apply-templates to newwo (case fixed), but newwo doesn't exist at that context. You'll either have to add */ or workorder/ to the apply-templates (like select="*/newwo") or change / to /* or /workorder in the match.
You match /newwo (case fixed again), but newwo is not the root element. Remove the /.
You do the following test: test="newwo != '0'", but newwo is already the current context. Use . or normalize-space() instead. (If you use normalize-space(), be sure to test against a string. (Quote the 1.))
Here's an updated example.
XML Input
<workorder>
<newwo>1</newwo>
</workorder>
XSLT 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:apply-templates select="newwo" />
</xsl:template>
<xsl:template match="newwo">
<xsl:text>{
newwo: "</xsl:text>
<xsl:choose>
<xsl:when test=".=1">NEW</xsl:when>
<xsl:otherwise>OLD</xsl:otherwise>
</xsl:choose>
<xsl:text>"
}</xsl:text>
</xsl:template>
</xsl:stylesheet>
Output
{
newwo: "NEW"
}
You try it as below
<?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" version="1.0">
<xsl:template match="/">
<xsl:choose>
<xsl:when test="/workorder/newwo = 1">
<xsl:text disable-output-escaping="no"> newwo:New</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text disable-output-escaping="no"> newwo:Old</xsl:text> </xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I would like to know how to replace the string with the abbreviations.
My XML looks like below
<concept reltype="CONTAINS" name="Left Ventricular Major Axis Diastolic Dimension, 4-chamber view" type="NUM">
<code meaning="Left Ventricular Major Axis Diastolic Dimension, 4-chamber view" value="18074-5" schema="LN" />
<measurement value="5.7585187646">
<code value="cm" schema="UCUM" />
</measurement>
<content>
<concept reltype="HAS ACQ CONTEXT" name="Image Mode" type="CODE">
<code meaning="Image Mode" value="G-0373" schema="SRT" />
<code meaning="2D mode" value="G-03A2" schema="SRT" />
</concept>
</content>
</concept>
and I am selecting some value from the xml like,
<xsl:value-of select="concept/measurement/code/#value"/>
Now what I want is, I have to replace cm with centimeter. I have so many words like this. I would like to have a xml for abbreviations and replace from them.
I saw one similar example here.
Using a Map in XSL for expanding abbreviations
But it replaces node text, but I have text as attribute. Also, it would be better for me If I can find and replace when I select text using xsl:valueof select instead of having a separate xsl:template. Please help. I am new to xslt.
I have created XSLT v "1.1". For abbreviations I have created XML file as you have mentioned:
Abbreviation.xml:
<Abbreviations>
<Abbreviation>
<Short>cm</Short>
<Full>centimeter</Full>
</Abbreviation>
<Abbreviation>
<Short>m</Short>
<Full>meter</Full>
</Abbreviation>
</Abbreviations>
XSLT:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" />
<xsl:param name="AbbreviationDoc" select="document('Abbreviation.xml')"/>
<xsl:template match="/">
<xsl:call-template name="Convert">
<xsl:with-param name="present" select="concept/measurement/code/#value"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="Convert">
<xsl:param name="present"/>
<xsl:choose>
<xsl:when test="$AbbreviationDoc/Abbreviations/Abbreviation[Short = $present]">
<xsl:value-of select="$AbbreviationDoc/Abbreviations/Abbreviation[Short = $present]/Full"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$present"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
INPUT:
as you have given <xsl:value-of select="concept/measurement/code/#value"/>
OUTPUT:
centimeter
You just need to enhance this Abbreviation.xml to keep short and full value of abbreviation and call 'Convert' template with passing current value to get desired output.
Here a little shorter version:
- with abbreviations in xslt file
- make use of apply-templates with mode to make usage shorter.
But with xslt 1.0 node-set extension is required.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="abbreviations_txt">
<abbreviation abbrev="cm" >centimeter</abbreviation>
<abbreviation abbrev="m" >meter</abbreviation>
</xsl:variable>
<xsl:variable name="abbreviations" select="exsl:node-set($abbreviations_txt)" />
<xsl:template match="/">
<xsl:apply-templates select="concept/measurement/code/#value" mode="abbrev_to_text"/>
</xsl:template>
<xsl:template match="* | #*" mode="abbrev_to_text">
<xsl:variable name="abbrev" select="." />
<xsl:variable name="long_text" select="$abbreviations//abbreviation[#abbrev = $abbrev]/text()" />
<xsl:value-of select="$long_text"/>
<xsl:if test="not ($long_text)">
<xsl:value-of select="$abbrev"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I have a xslt showing no whitespace as characters.
In this case show only %.
URL:
http://localhost:8888/tire/details/Bridgestone/ECOPIA%EP001S/Bridgestone,ECOPIA%EP001S,195--65%R15%91H,TL,ECO,0
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://www.w3.org/1999/xhtml" version="1.0">
<xsl:param name="extractorHost" />
<xsl:template match="/">
<links>
<xsl:apply-templates />
</links>
</xsl:template>
<xsl:template match="//x:form/x:a[#class='arrow-link forward']">
<xsl:variable name="url" select="translate(#href, ' ', '%20')"/>
<link href="{concat($extractorHost, $url)}" />
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
The correct URL should be:
http://localhost:8888/tire/details/Bridgestone/ECOPIA%20EP001S/Bridgestone,ECOPIA%20EP001S,195--65%20R15%2091H,TL,ECO,0
Is it wrong XSLT formed?. Thanks.
The XPath translate function doesn't work the way you think it does. That is, it is not a replace-string function.
It maps individual characters from one list to the corresponding characters in the other list.
So this,
translate(#href, ' ', '%20')
means, translate a space into %. The 20 part of the third argument is ignored.
Take a look here: XSLT string replace
You can use already existing templates that will let you use "replace" function.
here is a piece of code in XSL which tokenizes a text into fragments separated by interpunction and similar characters. I'd like to ask if there is a possibility to somehow capture the strings by which the text was tokenized, for example the comma or dot etc.
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs xdt err fn" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="GENERUJ">
<TEXT>
<xsl:variable name="text">
<xsl:value-of select="normalize-space(unparsed-text(#filename, 'UTF-8'))" disable-output-escaping="yes"/>
</xsl:variable>
<xsl:for-each select="tokenize($text, '(\s+("|\(|\[|\{))|(("|,|;|:|\s\-|\)|\]|\})\s+)|((\.|\?|!|;)"?\s*)' )">
<xsl:choose>
<xsl:when test="string-length(.)>0">
<FRAGMENT>
<CONTENT>
<xsl:value-of select="."/>
</CONTENT>
<LENGTH>
<xsl:value-of select="string-length(.)"/>
</LENGTH>
</FRAGMENT>
</xsl:when>
<xsl:otherwise>
<FRAGMENT_COUNT>
<xsl:value-of select="last()-1"/>
</FRAGMENT_COUNT>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</TEXT>
</xsl:template>
As you see the constructed tags CONTENTS, LENGTH, I'd like to add one called SEPARATOR if you know what I mean. I couldnt find any answer to this on the internet and I'm just a beginner with xsl transformations so I'm looking for a quick solution. Thank you in advance.
The tokenize() function doesn't allow you to discover what the separators were. If you need to know, you will need to use xsl:analyze-string instead. If you use the same regex as for tokenize(), this passes the "tokens" to the xsl:non-matching-substring instruction and the "separators" to the xsl:matching-substring instruction.