XSLT, Extract sub-string from xml using regex - regex

I am trying to apply XSLT on SVN log, I need to extract bug numbers from the commit messages. I am applying this regex on msg but get nothing back. What am I missing in XSLT?
Thank you in advance
Below is XML that I get from SVN:
<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry revision="265">
<author>dre</author>
<date>2015-04-13T02:35:25.246150Z</date>
<msg>modified code</msg>
</logentry>
<logentry revision="73283">
<author>john</author>
<date>2015-04-13T14:10:20.987159Z</date>
<msg>fixed bug DESK-1868</msg>
</logentry>
<logentry revision="73290">
<author>ron</author>
<date>2015-04-13T14:24:57.475711Z</date>
<msg>WEBAPP-1868 Fix for pallete list and settings dialog Selected Tab Index</msg>
</logentry>
</log>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>SVN Issues</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">ver</th>
<th style="text-align:left">author</th>
<th style="text-align:left">date</th>
<th style="text-align:left">ticket</th>
</tr>
<xsl:for-each select="log/logentry">
<tr>
<td><xsl:value-of select="#revision"/></td>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="date"/></td>
<td>
<xsl:variable name="messageValue" select="msg"/>
<xsl:analyze-string select="$messageValue"
regex="(DESK|TRS|PEK|WEBAPP)-\d{4}$">
<xsl:matching-substring>
<bug><xsl:value-of select="regex-group(1)"/></bug>
</xsl:matching-substring>
</xsl:analyze-string>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

http://www.w3.org/TR/xslt20/#analyze-string
Note: Because the regex attribute is an attribute value template, curly brackets within the regular expression must be doubled. For
example, to match a sequence of one to five characters, write
regex=".{{1,5}}". For regular expressions containing many curly
brackets it may be more convenient to use a notation such as
regex="{'[0-9]{1,5}[a-z]{3}[0-9]{1,2}'}", or to use a variable.
You do not want to anchor your expression to the end of the line using $ at the end of your expression. Otherwise the regex will only match when the message ends with an issue ID.
Use this regex expression to capture the entire bug number:
regex="((DESK|TRS|PEK|WEBAPP)-\d{{4}})"

Related

xsl:for-each inside xsl:for-each in table rows and columns

I've just started learning XML/XSL and I've hit a roadblock in one of my assignments. Tried Googling and searching over here but I can't seem to find a question that has a solution that is basic. so what I am trying is to display rows of bucket-type and room-types associated with it. can somebody please help
<list-inventory list-count="2">
<list list-type="Standard" list-order = "1" count-Types = "3">
<types type="BEN2D"></room>
<types type="BESH2D"></room>
<types type="HNK"></room>
</list>
<list list-type="Deluxe" list-order = "2" count-Types = "3">
<types type="SNK"></room>
<types type="TESTKD"></room>
<types type="TESTKD"></room>
</list>
<list-inventory>
I want table as below
Standard | Deluxe
BEN2D |SNK
BESH2D |TESTKD
HNK |TESTKD
I tried below xsl code but i see all list-type in single column and only 1st is being printing for all list-type:
<xsl:for-each select="/contents/list-inventory/list">
<tr>
<td class="alt-th" style="border:1px solid black">
<xsl:value-of select="#list-type"/>
</td>
</tr>
<tr>
<td style="border:1px solid black">
<xsl:for-each select="/contents/list-inventory/list/types">
<span><xsl:value-of select="#type"/></span>
<xsl:if test="position()!=last()">
<br/>
</xsl:if>
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
Can someone help me with xsl:for-each inside a xsl:for-each
It's too bad you did not post your expected result as code. I would assume that you want a separate row for each pair of values. As I stated in the comments, this is far from being trivial.
However, you could make it simpler if you are willing to settle for a single data row, where each cell contains all the values of the corresponding list (your attempt seems to suggest that this is what you actually tried to accomplish).
So, given a well-formed XML input:
XML
<list-inventory list-count="2">
<list list-type="Standard" list-order = "1" count-Types = "3">
<types type="BEN2D"/>
<types type="BESH2D"/>
<types type="HNK"/>
</list>
<list list-type="Deluxe" list-order = "2" count-Types = "3">
<types type="SNK"/>
<types type="TESTKD"/>
<types type="TESTKD"/>
</list>
</list-inventory>
you could do simply:
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:template match="/list-inventory">
<table border="1">
<!-- header -->
<tr>
<xsl:for-each select="list">
<th>
<xsl:value-of select="#list-type"/>
</th>
</xsl:for-each>
</tr>
<!-- body -->
<tr>
<xsl:for-each select="list">
<td>
<xsl:for-each select="types">
<xsl:value-of select="#type"/>
<br/>
</xsl:for-each>
</td>
</xsl:for-each>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
to get:
Result
<?xml version="1.0" encoding="UTF-8"?>
<table border="1">
<tr>
<th>Standard</th>
<th>Deluxe</th>
</tr>
<tr>
<td>BEN2D<br/>BESH2D<br/>HNK<br/>
</td>
<td>SNK<br/>TESTKD<br/>TESTKD<br/>
</td>
</tr>
</table>
which would render as:
I'm not sure how general you want your solution to be (i.e what inputs does it have to handle other than the example shown), but I would do something like:
<xsl:template match="list-inventory">
<xsl:variable name="list2" select="list[2]/types"/>
<xsl:for-each select="list[1]/types">
<xsl:variable name="position" select="position()"/>
<tr>
<td><xsl:value-of select="#type"/></td>
<td><xsl:value-of select="$list2[$position]/#type"/></td>
</tr>
</xsl:for-each>
</xsl:template>
Both the variables here are needed to avoid problems with context: the effect of an XPath expression depends on the context at the time it is evaluated, so you can evaluate a variable to capture information at the time you're in the right context.

Regex substring in XSLT

I'm trying to create a regex to get a substring in XSL 2.0 and this is the first time i'm working on XSL.
This is the expression that I'm trying to use to get the substring /(GS\.?\d{4}-\d{4}-\d{4})/g.
If I get any other value like GS.4354-4354-4543-5 or GS.4354-4354-4543-556 I want to extract the value that matches my regex.
If I use 'matches' it is just returning true or false, but my expectation is to trim the additional data. Any help is much appreciated.
I've also tried the following
<xsl:analyze-string select="$messageValue"
regex="(GS\.?\d{4}-\d{4}-\d{4})">
<xsl:matching-substring>
<bug><xsl:value-of select="regex-group(1)"/></bug>
</xsl:matching-substring>
</xsl:analyze-string>
whereas my $messageValue = GS.4354-4354-4543-5 and it is giving empty response.
Input - XML
<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry revision="265">
<author>dre</author>
<date>2015-04-13T02:35:25.246150Z</date>
<msg>GS.4554-0504-2089-4545</msg>
</logentry>
<logentry revision="73283">
<author>john</author>
<date>2015-04-13T14:10:20.987159Z</date>
<msg>GS.4554-0504-2089-2</msg>
</logentry>
<logentry revision="73290">
<author>ron</author>
<date>2015-04-13T14:24:57.475711Z</date>
<msg>GS-S.4554-0504-2089</msg>
</logentry>
</log>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
<html>
<body>
<h2>SVN Issues</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">ver</th>
<th style="text-align:left">author</th>
<th style="text-align:left">date</th>
<th style="text-align:left">ticket</th>
</tr>
<xsl:for-each select="log/logentry">
<tr>
<td><xsl:value-of select="#revision"/></td>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="date"/></td>
<td>
<xsl:variable name="messageValue" select="msg"/>
<xsl:analyze-string select="$messageValue"
regex="(GS\.?\d{4}-\d{4}-\d{4})">
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Expected Output -
<html>
<body>
<h2>SVN Issues</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">ver</th>
<th style="text-align:left">author</th>
<th style="text-align:left">date</th>
<th style="text-align:left">ticket</th>
</tr>
<tr>
<td>265</td>
<td>dre</td>
<td>2015-04-13T02:35:25.246150Z</td>
<td>GS.4554-0504-2089</td>
</tr>
<tr>
<td>73283</td>
<td>john</td>
<td>2015-04-13T14:10:20.987159Z</td>
<td>GS.4554-0504-2089</td>
</tr>
<tr>
<td>73290</td>
<td>ron</td>
<td>2015-04-13T14:24:57.475711Z</td>
<td>GS-S.4554-0504-2089</td>
</tr>
</table>
</body>
</html>
Solution from Martin is working when I test it in FreeFormatter.com, but for some reason when I deploy it on my cloud that is running linux this doesn't work. It is always returning empty string. Any one had any idea about it ?
The rexeg attribute can take attribute value templates which use {} as delimiters so to use the literally you need to double them
<xsl:analyze-string select="$messageValue"
regex="(GS\.?\d{{4}}-\d{{4}}-\d{{4}})">
<xsl:matching-substring>
<bug><xsl:value-of select="."/></bug>
</xsl:matching-substring>
</xsl:analyze-string>

What am I missing on this XSLT transformation?

I think it might be a silly question, but I read the documentation but it still not working for me.
I have this graphxml (generated my mvn):
<?xml version="1.0" encoding="UTF-8"?> <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key for="node" id="d0" yfiles.type="nodegraphics"/>
<key for="edge" id="d1" yfiles.type="edgegraphics"/>
<graph id="dependencies" edgedefault="directed">
<node id="966567431"><data key="d0"><y:ShapeNode><y:NodeLabel>myproject.mulesoft.services:utilitymgmt-services:mule:3.0.0-SNAPSHOT</y:NodeLabel></y:ShapeNode></data></node>
<node id="706960270"><data key="d0"><y:ShapeNode><y:NodeLabel>myproject.mulesoft.context:custom-runtime-context:jar:1.0.0-SNAPSHOT:compile</y:NodeLabel></y:ShapeNode></data></node>
<edge source="966567431" target="706960270"><data key="d1"><y:PolyLineEdge><y:EdgeLabel>compile</y:EdgeLabel></y:PolyLineEdge></data></edge>
<node id="1985178707"><data key="d0"><y:ShapeNode><y:NodeLabel>myproject.mulesoft.library:common-error-library:jar:2.0.0-SNAPSHOT:compile</y:NodeLabel></y:ShapeNode></data></node>
<node id="953191605"><data key="d0"><y:ShapeNode><y:NodeLabel>myproject.mulesoft.notification:utility-common-domains:jar:3.0.0-SNAPSHOT:compile</y:NodeLabel></y:ShapeNode></data></node>
<edge source="1985178707" target="953191605"><data key="d1"><y:PolyLineEdge><y:EdgeLabel>compile</y:EdgeLabel></y:PolyLineEdge></data></edge>
<edge source="966567431" target="1985178707"><data key="d1"><y:PolyLineEdge><y:EdgeLabel>compile</y:EdgeLabel></y:PolyLineEdge></data></edge>
</graph></graphml>
And all I'm trying to do at this point is to generate a HTML that shows a table with the dependencies like:
Dependencies
myproject.mulesoft.services:utilitymgmt-services:mule:3.0.0-SNAPSHOT
myproject.mulesoft.context:custom-runtime-context:jar:1.0.0-SNAPSHOT:compile
compile
myproject.mulesoft.library:common-error-library:jar:2.0.0-SNAPSHOT:compile
myproject.mulesoft.notification:utility-common-domains:jar:3.0.0-SNAPSHOT:compile
compile
compile
So this is the xsl I have:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Dependency</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Items</th>
</tr>
<xsl:for-each select="*">
<tr>
<td><xsl:value-of select="/"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
And I was expecting to have each item of the list into a separate TR TD.
But instead it's all into the same TR TD.
Items
com.quadreal.mulesoft.services:qr-identitymgmt-services:mule:3.0.0-SNAPSHOT com.quadreal.mulesoft.context:quadreal-runtime-context:jar:1.0.0-SNAPSHOT:compile compile com.quadreal.mulesoft.library:qr-common-error-library:jar:2.0.0-SNAPSHOT:compile com.quadreal.mulesoft.notification:quadreal-utility-common-domains:jar:3.0.0-SNAPSHOT:compile compile compile
Also even if I remove the for-each tag and keep only the
It still displaying the whole thing instead displaying only the first element.
Also tried to add a template for graph and for-each the elemtns, but then I don't even get the html. I get only the whole text for the dependencies.
Am I missing something or there is something with the graphml that is not properly generated?
I'm adding here the expected HTML code:
<html>
<body>
<h2>Dependency</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Items</th>
</tr>
<tr>
<td>myproject.mulesoft.services:utilitymgmt-services:mule:3.0.0-SNAPSHOT
</td>
</tr>
<tr>
<td>myproject.mulesoft.context:custom-runtime-context:jar:1.0.0-SNAPSHOT:compile
</td>
</tr>
<tr>
<td>compile</td>
</tr>
<tr>
<td>myproject.mulesoft.library:common-error-library:jar:2.0.0-SNAPSHOT:compile
</td>
</tr>
<tr>
<td>myproject.mulesoft.notification:utility-common-domains:jar:3.0.0-SNAPSHOT:compile
</td>
</tr>
<tr>
<td>compile</td>
</tr>
<tr>
<td>compile</td>
</tr>
</table>
</body>
</html>
You are getting only one table row, because you do:
<xsl:for-each select="*">
from the context of the / root node, established by:
<xsl:template match="/">
The / root node has only one child, and that is the graphml root element.
Perhaps you wanted to do:
<xsl:for-each select="*/*/*">
to create a row for every node and/or edge?
Note also that:
<xsl:value-of select="/"/>
makes no sense. It will return the entire text of the entire document. If you'll change it to:
<xsl:value-of select="."/>
you will get the expected result - at least in the given example.

Same xpath works on command line but not in xslt

I'm a beginning user of xslt and xpath. Using an xpath on a command line (Ubuntu 14.04) with a xml file works, but the very same xpath in an xslt file returns nothing. I'm working with Juniper Junos xml files. Any suggestions?
Thanks,
George
The xml file begins with:
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/12.3R8/junos">
<interface-information xmlns="http://xml.juniper.net/junos/12.3R8/junos-interface" junos:style="normal">
<physical-interface>
<name>fe-0/1/0</name>
<logical-interface>
<name>fe-0/1/0.0</name>
...
The command line that works in Ubuntu 14.04 is:
xpath -e "/rpc-reply/interface-information/physical-interface/logical-interface/name" interfaces.xml
The xslt file is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Interfaces</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Name</th>
</tr>
<xsl:for-each select="/rpc-reply/interface-information/physical-interface/logical-interface">
<tr>
<td><xsl:value-of select="name"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The problem here is quite simple. You are not using namespaces in your XPaths. Apparently your command line utility doesn't care, or evaluates XPaths based on the elements' QNames ignores default namespaces and does some other non-standard handling of namespaces as well.
The solution:
Declare prefixes at the top of your stylesheet:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:nbase="urn:ietf:params:xml:ns:netconf:base:1.0"
xmlns:junosi="http://xml.juniper.net/junos/12.3R8/junos-interface"
>
use those prefixes in your XPaths:
<xsl:for-each select="/nbase:rpc-reply/junosi:interface-information
/junosi:physical-interface/junosi:logical-interface">
<tr>
<td><xsl:value-of select="junosi:name"/></td>
</tr>
</xsl:for-each>

Need to find the parent node id

This is my sample input
<table id="1" style="width=100%">
<tr>
<td id="1">
<table id="2" style="width=50%">
<tr>
<td id="2">
</td>
</tr>
</table>
</td>
</tr>
</table>
I am using xslt1.0. when ever the template match 'td' is matched, i need to find the corresponding table id value..For example, If the td with id=1 is matched,i want to take style attribute value from table(id=1) and if the td with id=2 is matched,i want to take style attribute value from table(id=2). I have written ancestor::table/#style in my template, but both td are referring the styles of table with id=1.
I have written
ancestor::table/#style in my
template
You were close. Because there can be more than one table in the ancestor axis, you need to get the first one like in ancestor::table[1]/#style. Of course, if you are absolute sure there is always a chain of table -> tr -> td (not optional tbody) then you could go with #Flack's answer.
Assuming you are in 'td' context, use this XPath:
../../#style
Test XSLT against your sample:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="td">
<xsl:value-of select="../../#style"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Result:
width=100%width=50%
Try this XPath it works perfectly
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="td">
<xsl:value-of select="ancestor::table[1]/#style"/>
<xsl:apply-templates/>
</xsl:template>
Result:
width=100%width=50%