Retrieve XML Variable in XSL file and say YES if found - html

I have problems with the Xpath expression test="$roles/roles/role='HOBSCS1GB'" . Can anyone help in solving. Thanks
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<xsl:variable name="roles">
<roles>
<role>HOBSCS1ROI</role>
<role>HOBSCS1GB</role>
<role>HOBSCS1FT</role>
</roles>
</xsl:variable>
<xsl:if test="$roles/roles/role='HOBSCS1GB'">
<xsl:value-of select="'YES'"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Assuming you want to find if a the roles element has one or more role elements with text = 'HOBSCS1GB': (Works in Saxon)
<xsl:if test="$roles/roles[role='HOBSCS1GB']">
<xsl:value-of select="'YES'"/>
</xsl:if>
Note that certain parsers like Microsoft may require you to tell the parser that $roles is a result tree fragment, by using node-set(), like so: (Works in msxsl)
<xsl:stylesheet ... xmlns:msxsl="urn:schemas-microsoft-com:xslt" ... />
<xsl:if test="msxsl:node-set($roles)/roles[role='HOBSCS1GB']">
<xsl:value-of select="'YES'"/>
</xsl:if>
Or in xsltproc:
<xsl:stylesheet ... xmlns:exsl="http://exslt.org/common" ... />
<xsl:if test="exsl:node-set($roles)/roles[role='HOBSCS1GB']">
<xsl:value-of select="'YES'"/>
</xsl:if>

Related

Time format in XSLT 2.0

I worked with xslt 2.0 and Java( Saxon-HE ).Saxon-HE do not support xslt date-time format.I have current-date() and current-time() functions and I need them in the following format time(17:31), date(03/06).Please help me and give any suggestion hot to do it.Thanks a lot of
Please try the below tranformation:
<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="test">
<xsl:variable name="currenttime" select="current-dateTime()" as="xs:dateTime"/>
<xsl:value-of select="format-dateTime($currenttime,'[H]')"/><xsl:text>:</xsl:text><xsl:value-of select="format-dateTime($currenttime,'[m]')"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="format-dateTime($currenttime,'[M]')"/><xsl:text>/</xsl:text><xsl:value-of select="format-dateTime($currenttime,'[D]')"/>
</xsl:template>
</xsl:stylesheet>

XLST + XML -> Word <field name="foo">Value</foo>

I have a XML produce with MySQL Query Browser.
I'm trying to apply a XSLT to output the result into Word tables. One table for each record.
Here's a sample of my XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ROOT SYSTEM "Nessus.dtd">
<ROOT>
<row>
<field name="Niveau">Critique</field>
<field name="Name">Apache 2.2 < 2.2.15 Multiple Vulnerabilities</field>
</row>
<row>
<field name="Niveau">Critique</field>
<field name="VulnName">Microsoft Windows 2000 Unsupported Installation Detection</field>
</row>
<row>
<field name="Niveau">Haute</field>
<field name="VulnName">CGI Generic SQL Injection</field>
</row>
</ROOT>
For the XLST I've already found out that I need to do a for-each select
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="????"/>
Name : <xsl:value-of select="????"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When I do this loop I see the same number of empty table as there is <row></row> in my file.
But I haven't found the way to make the right "value-of select=". I've try the following without luck.
<xsl:value-of select="#name"/>
<xsl:value-of select="name"/>
<xsl:value-of select="#row/name"/>
<xsl:value-of select="row/#name"/>
<xsl:value-of select="#ROOT/row/name"/>
And a few other that I can't remember. Any idea what I need to craft the request to get the value in my resulting file?
I've just tried with :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="field/#Niveau"/>
Name : <xsl:value-of select="field/#name"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And it output this :
NIVEAU :
NAME : name
NIVEAU :
NAME : Niveau
NIVEAU :
NAME : Niveau
I would like this output :
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
Any help would be appreciated.
Thank you.
UPDATE
Now with this XSLT
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[#name = 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[#name = 'Name']"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
I get this output :
<?xml version="1.0"?>
NIVEAU :
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
As you can see the first field is empty. I could honestly live with that and fill it manually but if you see why this is happenning I'd be very happy :)
UPDATE
Using <xsl:value-of select="field[#name = 'foo']"/> gave me the value I wanted. I kept the for-each as it was easier to use (for me) inside a MS Word template.
for-each is generally code smell in XSLT. You most likely want a template, not a for-each loop:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="field">
<xsl:value-of select="#name"/> : <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
This template will produce the following output:
<root>
Niveau : Critique
name : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
Niveau : Critique
name : Microsoft Windows 2000 Unsupported Installation Detection
Niveau : Haute
name : CGI Generic SQL Injection
</root>
XSLT was designed for this pattern of use--many xsl:templates matching a small part of the source and applying other templates recursively. The most important and common template in this pattern is the identity template, which copies output. This is a good tutorial on XSLT coding patterns that you should read.
Update
Below is a complete solution that will produce text output (since that is what you seem to want, not XML output). I'm not sure xsl is the best language for this, but it works....
Notice that the only place we use for-each is for sorting to determine the length of the longest name. We use templates and pattern-matching selects to make all other loops implicit.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="newline"><xsl:text>
</xsl:text></xsl:variable>
<!-- determine the maximum length of the "name" field so we can pad with spaces for all shorter items -->
<xsl:variable name="max_name_len">
<xsl:for-each select="ROOT/row/field/#name">
<xsl:sort select="string-length(.)" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="string-length(.)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- for each row, apply templates then add a blank line -->
<xsl:template match="row">
<xsl:apply-templates/>
<xsl:value-of select="$newline"/>
</xsl:template>
<!-- for each field, apply template to name and add value, followed by a newline -->
<xsl:template match="field">
<xsl:apply-templates select="#name"/> : <xsl:value-of select="concat(., $newline)"/>
</xsl:template>
<!-- for each name, uppercase and pad with spaces to the right -->
<xsl:template match="field/#name">
<xsl:call-template name="padright">
<xsl:with-param name="text">
<xsl:call-template name="toupper">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="len" select="$max_name_len"/>
</xsl:call-template>
</xsl:template>
<!-- Utility function: uppercase a string -->
<xsl:template name="toupper">
<xsl:param name="text"/>
<xsl:value-of select="translate($text, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:template>
<!-- Utility function: pad a string to desired len with spaces on the right -->
<!-- uses a recursive solution -->
<xsl:template name="padright">
<xsl:param name="text"/>
<xsl:param name="len"/>
<xsl:choose>
<xsl:when test="string-length($text) < $len">
<xsl:call-template name="padright">
<xsl:with-param name="text" select="concat($text, ' ')"/>
<xsl:with-param name="len" select="$len"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This stylesheet produces the following output:
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
When you do <xsl:for-each select="ROOT/row">, the current context inside the loop is the rowelement. So in order to access the field name, you need to write, for example, <xsl:value-of select="field/#name"/>.
Since your XML contains several fields, you will still have to extend your XSLT file somewhat to iterate the fields, or (as Francis Avila suggested) write a template. Both methods are ok, though. The technical terms for the two approaches are "pull" and "push", respectively.
And of course, since you ultimately want to generate a word table, you will have to generate w:tr and w:tc elements, etc.
This stylesheet will give you exactly your desired output
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[#name eq 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[#name eq 'VulnName']"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
This is very specific to your input xml and output text, for example any <field> children of <row> other than 'Niveau' or 'VulnName' will be dropped from your report. A more generic solution could look like this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="field">
<xsl:value-of select="concat(upper-case(#name),': ',.)"/>
</xsl:template>
</xsl:stylesheet>
This solution though doesn't exactly match the whitespace formatting in your desired output, but it does capture all possible fields.

How have xsl:function return a string value including html tags

I am attempting to transpose a java function to an xsl:function spec.
The function basically places html tags around substrings.
I now bump into difficulties: using the java inline code this works perfectly, but I am unable to figure out how to prevent output escaping when using the xsl:function.
How can I achieve the output to contain the wanted html tags?
A simplified example of what I am trying to achieve is the following:
input parameter value "AB" should lead to a string A<b>B</b>, shown in html browser as AB of course.
Example function I tried is the below; but then the resulting string is A&lt ;b&gt ;B&lt ;/b&gt ; (note that I had to add blanks to prevent the entities from getting interpreted in this editor), which of course shows up in browers as A<b>B</b>.
Note that xsl:element cannot be used in the xsl:function code, because that has no effect; I want the string result of the function call to contain < and > characters, and then add the string result to the output result file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="http://localhost:8080/customFunctions">
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:function name="custom:test">
<xsl:param name="str"/>
<xsl:value-of select="substring($str,1,1)"/>
<xsl:text disable-output-escaping="yes"><![CDATA[<b>]]></xsl:text>
<xsl:value-of select="substring($str,2)"/>
<xsl:text disable-output-escaping="yes"><![CDATA[</b>]]></xsl:text>
</xsl:function>
<xsl:template match="/">
<xsl:element name="html">
<xsl:element name="body">
<xsl:value-of select="custom:test('AB')"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Here is an example, use sequence instead value-of and make sure your function returns nodes (which is usually simply done by writing literal result elements):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="http://localhost:8080/customFunctions"
exclude-result-prefixes="custom">
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:function name="custom:test">
<xsl:param name="str"/>
<xsl:value-of select="substring($str,1,1)"/>
<b>
<xsl:value-of select="substring($str,2)"/>
</b>
</xsl:function>
<xsl:template match="/">
<xsl:element name="html">
<xsl:element name="body">
<xsl:sequence select="custom:test('AB')"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

how to interpret HTML in XSL

I have the following xml
<results>
<first-name>Carl<first-name>
<data><b> This is carl's data </b></data>
</results>
How do I include the bold tags which is present in the <data> tag to be a part of the output but rendered as an HTML
When I say <xsl:value-of select="results/data"/> The output is
<b> This is carl's data </b>
I want to achieve "This is carl's data" as the output in bold.
Well <xsl:copy-of select="results/data/node()"/> is a start but if the requirement is part of a larger problem then you are better off writing a template for data elements which uses apply-templates to push the child nodes through some template(s) for copying HTML elements through to the output.
I am sure someone will let me know if I am being naive:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/results">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="first-name">
<xsl:value-of select="." />
<xsl:text>: </xsl:text>
</xsl:template>
<xsl:template match="data">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="b">
<b>
<xsl:value-of select="." />
</b>
</xsl:template>
</xsl:stylesheet>

umbraco macros in menu

I created a macro for my menu on the left and it is ok.
I want to use the same macros for the menu to the right without creating another.
What should I do?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:Stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:call-template name="drawNodes">
</xsl:call-template>
</xsl:template>
<xsl:template name="drawNodes">
<ul>
<xsl:for-each select="$currentPage/ancestor-or-self::root/node [string(data[#alias='posizione_menu']) = 'left']">
<xsl:choose>
<xsl:when test="$currentPage/ancestor-or-self::node/#id = current()/#id">
<li><xsl:value-of select="#nodeName"/></li>
</xsl:when>
<xsl:otherwise>
<li>
<a href="{umbraco.library:NiceUrl(#id)}" title="Accedi a {#nodeName}">
<xsl:text disable-output-escaping="yes"><![CDATA[«]]> </xsl:text>
<xsl:value-of select="#nodeName"/>
</a>
</li>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
If you want to reuse a macro you can easily do so by inserting into the .NET masterpage where you want to reuse it.
If you want different XHTML markup depending if it is on the left and right please let me know so I can help you out further.
Warren :)