XPath - replace element's name - xpath

Sample html:
<div>
<button class="show-more-button" data-url="https://www.example.com/">
View More
</button>
</div>
I need a scraping project to interpret the BUTTON element as A and data-url as href:
<div>
<A class="show-more-button" href="https://www.example.com/">
View More
</button>
</div>
Here is my attempt so far. Tried with bothe replace and tranlate:
//DIV/BUTTON[translate(DIV, "BUTTON", "A")][translate(DIV, "data-url", "href")][contains(#class, "show-more-button")]
How can I achieve it?

Applying an XSLT like this, you can transform the HTML and convert the button into a and #data-url into #href:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="button">
<a>
<xsl:apply-templates select="#*|node()"/>
</a>
</xsl:template>
<xsl:template match="#data-url">
<xsl:attribute name="href">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
If you only want to convert the #data-url of button elements, then adjust the generic match expression #data-url to button/#data-url.

Related

XSLT IF evaluation rules

From the XML file :
<store >
<tools>
<tool IDT="T1">
<container>B1</container>
<container>B2</container>
</tool>
<tool IDT="T2">
<container>B1</container>
</tool>
<tool IDT="T3">
<container>B2</container>
</tool>
</tools>
<boxes>
<box IDB="B1" height="10" width="20" length="30" weight="4"/>
<box IDB="B2" height="5" width="40" length="30" weight="2"/>
</boxes>
</store>
I try to display for each box the list of tools that go into each box. For that, I wrote the following XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output
method="html"
encoding="UTF-8"
doctype-public="-//W3C//DTD HTML 4.01//EN"
doctype-system="http://www.w3.org/TR/html4/strict.dtd"
indent="yes" />
<xsl:template match="/">
<html>
<head>
<title>Boxes contents</title>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Boxes contents</h1>
<ul>
<xsl:apply-templates select="/store/boxes/box" />
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="box" >
<li><xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:call-template name="findTools" >
<xsl:with-param name="currentBOX" select="#IDB"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="findTools" >
<xsl:param name="currentBOX" />
<xsl:for-each select="/store/tools/tool/container" >
<xsl:if test="container = $currentBOX" >
<br><xsl:value-of select="#IDT"/></br>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When I do it, I never see the tools. In debug under OXYGEN, I see that the IF is never true. I do not understand why? I start in XPath and XSLT, thanks for your help
You already are at a <container> element inside the <xsl:for-each>. There are no children, so selecting another <container> inside the <xsl:if> won't return anything.
You mean to execute your check from the <tool> node.
<xsl:for-each select="/store/tools/tool">
<xsl:if test="container = $currentBOX">
<xsl:value-of select="#IDT"/><br />
</xsl:if>
</xsl:for-each>
which is easier written as
<xsl:for-each select="/store/tools/tool[container = $currentBOX]">
<xsl:value-of select="#IDT"/><br />
</xsl:for-each>
Overall a more straight-forward way to write the two templates would be this:
<xsl:template match="box">
<li>
<xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:apply-templates select="/store/tools/tool[container = current()/#IDB]" />
</xsl:template>
<xsl:template match="tool">
<xsl:value-of select="#IDT"/><br />
</xsl:template>
And alternatively you can use an <xsl:key> to index <tool> elements by their <container> value:
<xsl:key name="kToolByContainer" match="/store/tools/tool" use="container" />
<xsl:template match="box">
<li>
<xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:apply-templates select="key('kToolByContainer', #IDB)" />
</xsl:template>
<xsl:template match="tool">
<xsl:value-of select="#IDT"/><br />
</xsl:template>

Match URL-Pattern in XSLT 1 Attribute using XPATH

Have this given piece of RDF/XML (can’t change it…):
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cel="http://namespaces.semaworx.org/content#" xmlns:dct="http://purl.org/dc/terms/" xmlns:i18n21="http://apache.org/cocoon/i18n/2.1">
<cel:page>
<dct:hasPart>
<cel:Element rdf:about="http://resources.semaworx.eu/content/element/start_navigation_home">
<cel:hasStructureI18n rdf:parseType="Literal"><i18n21:translate><i18n21:text key="start_navigation_home">Start</i18n21:text></i18n21:translate></cel:hasStructureI18n>
<i18n21:key>TheI18nKey</i18n21:key>
</cel:Element>
</dct:hasPart>
</cel:page>
</rdf:RDF>
Now I need to XSLT template-match specific "i18n21:key"-Elements based upon the URI in the "cel:Element"’s "rdf:about" attribute.
Best approach this far was something like
"cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key"
So this is an excerpt from the XSLT:
<xsl:template match="dct:hasPart" mode="layoutject_navigationMain_top">
<header id="navbar">
<nav>
<xsl:if test="$device != 'phone'">
<xsl:apply-templates select="cel:Element" mode="layoutject_languageSwitch"/>
<xsl:apply-templates select="cel:Element" mode="layoutject_navigationMain_inlineContent"/>
</xsl:if>
</nav>
</header>
</xsl:template>
<xsl:template match="cel:Element" mode="layoutject_navigationMain_inlineContent">
<ul id="main">
<xsl:apply-templates select="cel:Element[contains(#rdf:about,'urbanHOTBED/element/start_navigation_home')]/i18n21:key" mode="layoutject_navigationMain_singleItem" />
</ul>
</xsl:template>
<xsl:template match="cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key" mode="layoutject_navigationMain_singleItem">
<li class="ff">
<a href="/" title="back to Homepage" i18n21:attr="href title" class="nav_start">
<xsl:value-of select="cel:Element[contains(#rdf:about,'element/start_navigation_home')]/i18n21:key"/>
</a>
</li>
</xsl:template>
It’s only the last template, which won’t match as hoped for.
This far, I have tried being less specific in the "apply-templates" clause, as well as matching the full URI instead of using "contains".

Finding nested elements with XPath (same type)

I can’t figure out how to find nested elements of the same type. Typically, if I have 7 levels of headers and want to transform them with XSLT to h1–h7 heads, how to choose them with XPath—I can’t make out nothing better than div/div/div/head but this seems really clumsy.
This transformation:
<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="div/head">
<xsl:element name="h{count(ancestor::div)}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<div>
<head>1</head>
<div>
<head>2-1</head>
<div>
<head>3-1</head>
</div>
</div>
<div>
<head>2-2</head>
</div>
</div>
produces the wanted, correct result:
<div>
<h1>1</h1>
<div>
<h2>2-1</h2>
<div>
<h3>3-1</h3>
</div>
</div>
<div>
<h2>2-2</h2>
</div>
</div>

SharePoint 2013 Blog: sort posts by authors

I'm trying to make a custom filter which sorts on authors (users) in the SharePoint 2013 blog. I'm working with XSL dataview and it's exported to a web part. I have a column called Author which gets the information from Created By. When I click on a user in the web part it shows all posts instead of the selected author. The URL is mysite/default.aspx?Author=FirstName LastName".
Code (default.aspx):
<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<xsl:call-template name="dvt_1"/>
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">RepForm3</xsl:variable>
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[not(#Author.title=preceding-sibling::Row/#Author.title)]" />
<xsl:call-template name="dvt_1.header">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
<div class="blogRefineByAuthorContainer">
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="dvt_1.header">
<xsl:param name="Rows" />
<div class="blogRefineByAuthorEveryAuthor">Everyone</div>
</xsl:template>
<xsl:template name="dvt_1.body">
<xsl:param name="Rows"/>
<xsl:for-each select="$Rows">
<xsl:call-template name="dvt_1.rowview" />
</xsl:for-each>
</xsl:template>
<xsl:template name="dvt_1.rowview">
<div class="blogRefineByAuthorAuthorTitle">
<xsl:value-of select="#Author.title" />
</div>
</xsl:template>
Any ideas of what it could be? Between the first and last name there is a space in the URL, but I don't think it makes any sense. I have tried with %20 without any result.

Extract image from CDATA-xml rss file into xslt

I need show with xslt information about an xml RSS feed.
The xml source is:
<description><![CDATA[<p>
<img style="margin: 10px;
float: left;" alt="Nuevo modelo general de negocio"
src="http://mysite.es/images/figure1.jpg" width="196" height="147" />
La compañía apuesta por un marcado giro en el modelo]]>
</description>
I´m using:
<xsl:value-of select="description" disable-output-escaping="yes"/>
But the rendering is not good because I need show a resize image, with size, for example 70x70.
I´ve tried with this but its wrong:
<xsl:value-of select="replace("description","images/","images/resized/images/")"
disable-output-escaping="yes"/>
The perfect solution for me would be to extract separated, both the src property and the text from the tag.
Regards,
María
If your xml always is like your example then you should be able to use something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xsl">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<div>
<xsl:apply-templates select="rss/channel"/>
</div>
</xsl:template>
<xsl:template match="rss/channel">
<ul>
<xsl:apply-templates select="item"/>
</ul>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="item_link" select="link"/>
<xsl:variable name="item_title" select="substring-after(description, '/>')"/>
<xsl:variable name="item_image" select="substring-before(substring-after(description, 'src="'), '"')" />
<li>
<a href="{$item_link}">
<img alt="" src="{$item_image}" width="70" height="70" />
<xsl:value-of select="$item_title"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>

Resources