I was wondering if anyone knew if there was a simple way to change all of my strings in my xml file to arrays?
Example:
//This is the string I need to change:
<string name="sample1">value1, value2, value3, value4, value5</string>
//This is the way I need it to be:
<array name="sample1">
<item>value1</item>
<item>value2</item>
<item>value3</item>
<item>value4</item>
<item>value5</item>
</array>
My problem is not that I do not know how to manually do it. But I am looking for a way to simulate this process more easily because I have 120 strings with 25-90 values in each.
A good example would be converting multiple images extentions with a single click using an add-on to GIMP that simulates that process for you for each image.
Would anyone who understands what I am asking, know a way to do this for string to array?
This XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<array>
<xsl:attribute name="name">
<xsl:value-of select="string/#name"/>
</xsl:attribute>
<xsl:apply-templates/>
</array>
</xsl:template>
<xsl:template match="string/text()" name="tokenize">
<xsl:param name="text" select="."/>
<xsl:param name="sep" select="','"/>
<xsl:choose>
<xsl:when test="not(contains($text, $sep))">
<item>
<xsl:value-of select="normalize-space($text)"/>
</item>
</xsl:when>
<xsl:otherwise>
<item>
<xsl:value-of select="normalize-space(substring-before($text, $sep))"/>
</item>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $sep)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
applied to this XML:
<?xml version="1.0" encoding="UTF-8"?>
<string name="sample1">value1, value2, value3, value4, value5</string>
gives this output:
<?xml version="1.0" encoding="UTF-8"?>
<array name="sample1">
<item>value1</item>
<item>value2</item>
<item>value3</item>
<item>value4</item>
<item>value5</item>
</array>
The XSLT is using a recursive template going through your string values and splitting them at the comma.
This can be done with XSLT 2.0 as simply as:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<array name="{#name}">
<xsl:for-each select="tokenize(., ',\s*')">
<item><xsl:value-of select="."/></item>
</xsl:for-each>
</array>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<string name="sample1">value1, value2, value3, value4, value5</string>
the wanted, correct result is produced:
<array name="sample1">
<item>value1</item>
<item>value2</item>
<item>value3</item>
<item>value4</item>
<item>value5</item>
</array>
Related
Below is the XML Input payload. I'm looking for an xml output should have "type" element inside the each Address node. Below is the incoming request XML
<rsp:response xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1">
<res:employee>
<resp:Employee>
<resp:FirstName>abc</resp:FirstName>
<resp:middleName></resp:middleName>
<resp:details>
<resp:Details>
<resp:type>postal</resp:type>
<resp:Addresses>
<resp:Address>
<resp:country>XYZ</resp:country>
</resp:Address>
</resp:Addresses>
</resp:Details>
<resp:Details>
<resp:type>ofc</resp:type>
<resp:Addresses>
<resp:Address>
<resp:country>XYZ</resp:country>
</resp:Address>
</resp:Addresses>
</resp:Details>
</resp:details>
</resp:Employee>
</res:employee>
</rsp:response>
Here is the XSLT used and it is not giving desired output. Using this XSLT all "type" elements is reflecting in each address block.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1"
version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='Addresses']/*[local-name()='Address']">
<xsl:copy>
<xsl:apply-templates/>
<xsl:for-each select="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='type']">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='type']"/>
</xsl:stylesheet>
Desired Output XML
<rsp:response
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1">
<res:employee>
<resp:Employee>
<resp:FirstName>abc</resp:FirstName>
<resp:middleName/>
<resp:details>
<resp:Details>
<resp:Addresses>
<resp:Address>
<resp:country>XYZ</resp:country>
<resp:type>postal</resp:type>
</resp:Address>
</resp:Addresses>
</resp:Details>
<resp:Details>
<resp:Addresses>
<resp:Address>
<resp:country>XYZ</resp:country>
<resp:type>ofc</resp:type>
</resp:Address>
</resp:Addresses>
</resp:Details>
</resp:details>
</resp:Employee>
</res:employee>
</rsp:response>
Try it this way:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:resp="resp.com/details/v1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="resp:Address">
<xsl:copy>
<xsl:apply-templates/>
<xsl:copy-of select="../../resp:type"/>
</xsl:copy>
</xsl:template>
<xsl:template match="resp:type"/>
</xsl:stylesheet>
Re your attempt:
There should never be a need to use a hack like *[local-name()='type'];
You should find out what // means.
I have an rss feed which is pulling from an abandoned 'Joke of the day' blog. Because the blog is no longer updating, I want to iterate through the list and display a different item each day, ideally in chronological order.
How do I identify the 'first' item in the list (the oldest post) and then show the next item each day?
The rss source is here: http://feeds.feedburner.com/DailyJokes-ACleanJokeEveryday?format=xml
The full list is here: http://dailyjokes.somelifeblog.com/
My XSL code is here, and currently displays the item at position 2, which is the most recent post:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:apply-templates select="//item[position() < 2]"/>
</xsl:template>
<xsl:template match="item">
<content-item>
<h1><xsl:value-of select="substring-before(title, ' #Joke')"/></h1>
<p><xsl:value-of select="substring-before(description, '<a href')" disable-output-escaping="yes"/></p>
</content-item>
</xsl:template>
</xsl:stylesheet>
I am surfacing this feed in a SharePoint 2013 RSS webpart
My goal is to display a different item each day but I might settle for simple randomization. Also if anybody can suggest a free or for-cost 'Joke of the day' site which is appropriate for my work intranet, that would be appreciated!
My goal is to display a different item each day
To accomplish your goal, your processor needs to know the current date.
The following is a minimized example showing how to use the date in order to retrieve a different item every day:
XML
<rss>
<channel>
<item>
<title>Alpha</title>
</item>
<item>
<title>Bravo</title>
</item>
<item>
<title>Charlie</title>
</item>
<item>
<title>Delta</title>
</item>
<item>
<title>Echo</title>
</item>
</channel>
</rss>
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:strip-space elements="*"/>
<xsl:param name="current-datetime">2017-04-27T00:00:00</xsl:param>
<xsl:template match="/rss">
<xsl:variable name="JDN">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$current-datetime"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="n" select="count(channel/item)" />
<output>
<xsl:apply-templates select="channel/item[$JDN mod $n + 1]"/>
</output>
</xsl:template>
<xsl:template match="item">
<item>
<xsl:value-of select="title"/>
</item>
</xsl:template>
<xsl:template name="JDN">
<xsl:param name="date"/>
<xsl:param name="year" select="substring($date, 1, 4)"/>
<xsl:param name="month" select="substring($date, 6, 2)"/>
<xsl:param name="day" select="substring($date, 9, 2)"/>
<xsl:param name="a" select="floor((14 - $month) div 12)"/>
<xsl:param name="y" select="$year + 4800 - $a"/>
<xsl:param name="m" select="$month + 12*$a - 3"/>
<xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
</xsl:stylesheet>
In this example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<item>Bravo</item>
</output>
Live demo: http://xsltransform.net/pNmBxZK
If your processor supports the EXSLT date:date-time()extension function, you can modify your stylesheet's header to:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="date">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="current-datetime" select="date:date-time()"/>
For SharePoint, I am guessing you would need to use the TodayIso function in the ddwrt namespace instead.
I am trying to create an XSLT that will convert an array into unique sequential elements. I am probably not explaining this correctly so I will show you:
Current XML
<?xml version="1.0" encoding="UTF-8"?>
<DocumentRequests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PlanID>20151014_103605</PlanID>
<LetterType>
<Fund>Yes</Fund>
<Adding>Yes</Adding>
<Bau>Yes</Bau>
</LetterType>
<PlanNumbers>
<PlanNumber>A01</PlanNumber>
<PlanNumber>A02</PlanNumber>
<PlanNumber>A03</PlanNumber>
<PlanNumber>A04</PlanNumber>
<PlanNumber>A05</PlanNumber>
<PlanNumber>A06</PlanNumber>
<PlanNumber>456</PlanNumber>
</PlanNumbers>
</DocumentRequests>
Current XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.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="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<SourceFeedbackTransformed>
<PlanAdminID><xsl:value-of select="PlanAdminID" /></PlanAdminID>
<xsl:for-each select="LetterType">
<xsl:copy-of select="*" copy-namespaces="no"/>
</xsl:for-each>
<xsl:for-each select="PlanNumbers">
<xsl:copy-of select="*" copy-namespaces="no"/>
</xsl:for-each>
</SourceFeedbackTransformed>
</xsl:template>
</xsl:stylesheet>
Current output
<?xml version="1.0" encoding="UTF-8"?>
<SourceFeedbackTransformed xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<PlanAdminID/>
<Fund>Yes</Fund>
<Adding>Yes</Adding>
<Bau>Yes</Bau>
<PlanNumber>A01</PlanNumber>
<PlanNumber>A02</PlanNumber>
<PlanNumber>A03</PlanNumber>
<PlanNumber>A04</PlanNumber>
<PlanNumber>A05</PlanNumber>
<PlanNumber>A06</PlanNumber>
<PlanNumber>456</PlanNumber>
</SourceFeedbackTransformed>**
Desired Output
<?xml version="1.0" encoding="UTF-8"?>
<SourceFeedbackTransformed xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<PlanAdminID/>
<Fund>Yes</Fund>
<Adding>Yes</Adding>
<Bau>Yes</Bau>
<PlanNumber1>A01</PlanNumber1>
<PlanNumber2>A02</PlanNumber2>
<PlanNumber3>A03</PlanNumber3>
<PlanNumber4>A04</PlanNumber4>
<PlanNumber5>A05</PlanNumber5>
<PlanNumber6>A06</PlanNumber6>
<PlanNumber7>456</PlanNumber7>
</SourceFeedbackTransformed>
As you can see the Array with 7 values has been converted to 7 different elements.
Thank you for your help.
Cheers,
You can get the result you're after quite easily by:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/DocumentRequests">
<SourceFeedbackTransformed>
<PlanAdminID><xsl:value-of select="PlanID" /></PlanAdminID>
<xsl:copy-of select="LetterType/*" copy-namespaces="no"/>
<xsl:for-each select="PlanNumbers/PlanNumber">
<xsl:element name="PlanNumber{position()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</SourceFeedbackTransformed>
</xsl:template>
</xsl:stylesheet>
Note:
I have changed your:
<xsl:value-of select="PlanAdminID" />
to:
<xsl:value-of select="PlanID" />
as there is no PlanAdminID element in your input. If you really want to output an empty <PlanAdminID/> element as shown in your requested output, then you could do so directly, without fetching the value of a non-existing node.
As the reverse case of this post, how it's possible to transform content of an XML document to array using XSLT.
For this:
<Records>
<item>value1</item>
<item>value2</item>
<item>value3</item>
<item>value4</item>
<item>value5</item>
</Records>
The desired result is something like this:
[value1, value2, value3, value4, value5]
What's the idea?
Hope this helps..
<?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="text"/>
<xsl:template match="/">
<xsl:variable name="countItems" select="count(Records/item)"/>
[<xsl:for-each select="Records/item">
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="position()=$countItems"/>
<xsl:otherwise>,</xsl:otherwise>
</xsl:choose>
</xsl:for-each>]
</xsl:template>
</xsl:stylesheet>
XSLT 1.0 can be used to generate a resultant xml,text or HTML file from the source xml file.
You can get the resultant data from the file created via XSLT
In WSO2 ESB Proxy service, how can i iterate based on integer value from some webservice response, just like "foreach":
For example such response message:
<Response>
<noOfcustomers>10</noOfCustomers>
</Response>
I need to iterate 10 times (based on the number of customers)
Is this possible? How can i achieve this?
Thanks for your help!
I've not found a clean way to do this, but here's a messy solution.
First you need an XSLT transformation.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xsl xsi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="iterations"/>
<xsl:template name="for.loop">
<xsl:param name="i"/>
<xsl:param name="count"/>
<!--begin_: Line_by_Line_Output -->
<xsl:if test="$i <= $count">
<iteration>
<xsl:value-of select="$i"/>
</iteration>
</xsl:if>
<!--begin_: RepeatTheLoopUntilFinished-->
<xsl:if test="$i <= $count">
<xsl:call-template name="for.loop">
<xsl:with-param name="i">
<xsl:value-of select="$i + 1"/>
</xsl:with-param>
<xsl:with-param name="count">
<xsl:value-of select="$count"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<iterations>
<xsl:call-template name="for.loop">
<xsl:with-param name="i">1</xsl:with-param>
<xsl:with-param name="count"><xsl:value-of select="$iterations"/></xsl:with-param>
</xsl:call-template>
</iterations>
</xsl:template>
</xsl:stylesheet>
Then you use the transformation in your sequence like this:
<inSequence>
<xslt key="conf:/repository/test/iterations.xslt">
<property name="iterations" expression="//noOfcustomers"/>
</xslt>
<iterate expression="//iterations/iteration" sequential="true">
<target>
<sequence>
</sequence>
</target>
</iterate>
</inSequence>
The sequence in the iterate mediator will run for each element in "iterations". The drawback to this approach is that you are replacing the message body with the iteration XML, so you have to use the enrich meditor before the transformation to save the original message to a property if you wish to reuse it.
You can iterate based on xpath. But currently we don't have counter support. What is your actual usecase?
This is supported with ForEach mediator from ESB 4.9 onwards