How to create xml hierarchy from string path - html

I have an XML file with the structure like this
<Items>
<Item ID="1">
<Folder>Organisms\Pets\Cat</Folder>
</Item>
<Item ID="2">
<Folder>Organisms\Pets\Horse</Folder>
</Item>
<Item ID="3">
<Folder>Organisms\Pets\Fish</Folder>
</Item>
<Item ID="4">
<Folder>Organisms\Pets\Dog</Folder>
</Item>
</Items>
How do I create a hierarchy structure for the folders using xslt ?? So it will look like this:
<Folder>
<Organisms>
<Pets>
<Dog/>
<Cat/>
<Horse/>
<Fish/>
</Pets>
</Organisms>
</Folder>
Thanks for reading :)
-----------------Update-------------------------------------------
<xsl:template match="Item" name="split">
<xsl:param name="pText" select="Folder"/>
<xsl:if test="string-length($pText)">
<ul>
<li>
<xsl:value-of select="substring-before(concat($pText,'\'),'\')"/>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, '\')"/>
</xsl:call-template>
</li>
</ul>
</xsl:if>
</xsl:template>
I tried this and some how it works, but only problem is duplication. I don't know how to group the Organism as 1 node and Pets as another node

Related

XSLT sibling recursion by column span that can detect if the succeeding column region is occupied

I have a partially working XSLT that groups my elements by columns according to column break. My elements are displayed in one column until a <ColumnBreak> is encountered, which then makes the succeeding items rendered in a new column to the right.
Now I want to extend this XSLT to achieve the concept of column span based on the width of my items, so I followed the sample implementation from this topic. Furthermore, if a region is already occupied in the next column due to the width span of the previous element, the succeeding elements following the ColumnBreak shall be displayed below the already occupied region.
XML:
<?xml version="1.0" encoding="utf-8" ?>
<Group>
<Items>
<Item>
<Display>Item 1</Display>
</Item>
<Item>
<Display>Item 2</Display>
<Width>2</Width>
</Item>
<Item>
<Display>Item 3</Display>
</Item>
<ColumnBreak />
<Item>
<Display>Item 4</Display>
</Item>
<Item>
<Display>Item 5</Display>
</Item>
<ColumnBreak />
<Item>
<Display>Item 6</Display>
</Item>
<Item>
<Display>Item 7</Display>
</Item>
</Items>
</Group>
XSLT:
<?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"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"
exclude-result-prefixes="msxsl xsi">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Group">
<xsl:apply-templates select="Items"/>
</xsl:template>
<xsl:key name="cell-by-row" match="cell" use="#row" />
<xsl:key name="cell-by-col" match="cell" use="concat(#row, '|', #col)" />
<xsl:template match="Items">
<div>
<xsl:variable name="cells">
<xsl:apply-templates select="*[1]" mode="item-sibling">
<xsl:with-param name="row" select="1"/>
<xsl:with-param name="col" select="1"/>
<xsl:with-param name="index" select="1"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:call-template name="generate-rows">
<xsl:with-param name="cells" select="$cells" />
<xsl:with-param name="current-row" select="1"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="generate-rows">
<xsl:param name="cells" />
<xsl:param name="current-row" />
<xsl:param name="last-row" />
<xsl:for-each select="exsl:node-set($cells)/cell[count(. | key('cell-by-row', #row)[1]) = 1]">
<xsl:for-each select="key('cell-by-row', #row)[count(. | key('cell-by-col', concat(#row, '|', #col))[1]) = 1]">
<xsl:for-each select="key('cell-by-col', concat(#row, '|', #col))">
<xsl:if test="not(#empty)">
<div row="{#row}" col="{#col}" index="{#index}" width="{#width}">
<xsl:apply-templates select="." mode="item">
</xsl:apply-templates>
</div>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="item-sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:param name="index"/>
<xsl:param name="previous-cells" select="some-dummy-node-to-make-this-a-node"/>
<xsl:variable name="width">
<xsl:call-template name="width-template" />
</xsl:variable>
<xsl:variable name="colliding-cell" select="exsl:node-set($previous-cells)/cell[#row = $row and #col < $col and #index > $index and #width + #col > $col]" />
<xsl:choose>
<xsl:when test="$colliding-cell">
<xsl:apply-templates select="self::node()" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
<xsl:with-param name="index" select="$colliding-cell/#index + 1"/>
<xsl:with-param name="previous-cells" select="$previous-cells"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="current-cell">
<cell row="{$row}" col="{$col}" index="{$index}" width="{$width}">
<xsl:copy-of select="exsl:node-set(.)"/>
</cell>
</xsl:variable>
<xsl:variable name="new-cells">
<xsl:copy-of select="$previous-cells"/>
<xsl:copy-of select="$current-cell"/>
</xsl:variable>
<xsl:copy-of select="$current-cell"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="previous-cells" select="$new-cells"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ColumnBreak" mode="item-sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:param name="index"/>
<xsl:param name="previous-cells"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col + 1"/>
<xsl:with-param name="index" select="1" />
<xsl:with-param name="previous-cells" select="$previous-cells"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template name="width-template">
<xsl:choose>
<xsl:when test="Width">
<xsl:value-of select="Width" />
</xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Item" mode="item">
<xsl:value-of select="Display" />
</xsl:template>
</xsl:stylesheet>
EXPECTED RESULT*:
Scenario 1: Item 2 Width = 2
Scenario 2: Item 2 Width = 2, Item 4 Width = 2
*For illustration purposes, I used HTML table in my scenario screenshots, but basically the items need not to be precisely aligned by row because my elements may vary by height. The ultimate goal is to group them into columns.
Current Output:
My current XSLT produces a raw matrix which shows the column assignment of the element and its corresponding width. How do I convert this matrix to a layout of HTML <div> that will look similar to the expected results above?
My XSLT Fiddle: https://xsltfiddle.liberty-development.net/6pS26mX/1
Thank you!

XLT cross referencing between xml tags to decide what a class property should be added

I have an xml file, that describes a conversation between Agent and Client. Both parties have a userId, that is assigned in the newParty tag.
Subsequent messages and notices, refer to this userId. I would like for when a message or a notice is processed, that a lookup is done by using the userId, to add the string "Agent" or "Client" to the class property of the generated HTML.
<?xml version="1.0"?>
<chatTranscript startAt="2016-10-06T09:16:40Z" sessionId="0001GaBYC53D000K">
<newParty userId="007957F616780001" timeShift="1" visibility="ALL" eventId="1">
<userInfo personId="" userNick="John Doe" userType="CLIENT" protocolType="FLEX" timeZoneOffset="120"/>
<userData>
<item key="GMSServiceId">5954d184-f89d-4f44-8c0f-a772d458b353</item>
<item key="IdentifyCreateContact">3</item>
<item key="MediaType">chat</item><item key="TimeZone">120</item>
<item key="_data_id">139-e9826bf5-c5a4-40e5-a729-2cbdb4776a43</item>
<item key="firstName">John</item><item key="first_name">John</item>
<item key="lastName">Doe</item>
<item key="last_name">Doe</item>
<item key="location_lat">37.8197</item>
<item key="location_long">-122.4786</item>
<item key="userDisplayName">John Doe</item>
</userData>
</newParty>
<newParty userId="0079581AF56C0025" timeShift="20" visibility="ALL" eventId="2">
<userInfo personId="1" userNick="allendei" userType="AGENT" protocolType="BASIC" timeZoneOffset="120"/>
</newParty>
<message userId="007957F616780001" timeShift="25" visibility="ALL" eventId="3">
<msgText msgType="text" treatAs="NORMAL">This is message one.</msgText>
</message>
<message userId="0079581AF56C0025" timeShift="35" visibility="ALL" eventId="4">
<msgText msgType="text" treatAs="NORMAL">This is message two.</msgText>
</message>
<notice userId="0079581AF56C0025" timeShift="40" visibility="ALL" eventId="5">
<noticeText noticeType="USER_CUSTOM">This is notice one.</noticeText>
</notice>
<notice userId="007957F616780001" timeShift="58" visibility="ALL" eventId="6">
<noticeText noticeType="USER_CUSTOM">This is notice two.</noticeText>
</notice>
<partyLeft userId="007957F616780001" timeShift="90" visibility="ALL" eventId="4" askerId="007957F616780001">
<reason code="3">left due to disconnect</reason>
</partyLeft>
... and my xlt is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:template match="/chatTranscript">
<html>
<header><xsl:value-of select="#sessionId" /></header>
<xsl:apply-templates select="newParty" />
<xsl:apply-templates select="message/msgText" />
<xsl:apply-templates select="notice/noticeText" />
<xsl:apply-templates select="partyLeft/reason" />
</html>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='CLIENT']">
<div class="Client" id="{#userId}">
<label>Client: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='AGENT']">
<div class="Client" id="{#userId}">
<label>Agent: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="msgText">
<div class="Messages" id="{../#eventId}">
<label>Message: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
<xsl:template match="noticeText">
<div class="Notices" id="{../#eventId}">
<label>Notice: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
<xsl:template match="reason">
<div class="Notices" id="{../#eventId}">
<label>Reason: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
the desired output is as follows - where the class property(Agent or Client) of Messages and Notices are lookup up via the userID in the newParties at the top.
<html>
<header>0001GaBYC53D000K</header>
<div class="Client" id="007957F616780001"><label>Client: John Doe</label></div>
<div class="Client" id="0079581AF56C0025"><label>Agent: allendei</label></div>
<div class="Messages,Client" id="3"><label>Message: This is message one.</label></div>
<div class="Messages,Agent" id="4"><label>Message: This is message two.</label></div>
<div class="Notices,Agent" id="5"><label>Notice: This is notice one.</label></div>
<div class="Notices,Client" id="6"><label>Notice: This is notice two.</label></div>
<div class="Notices,Client" id="4"><label>Reason: left due to disconnect</label></div>
XSLT has a built-in mechanism for performing lookups. Start by defining a key as:
<xsl:key name="party" match="newParty" use="#userId" />
then use it as shown in the following example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:key name="party" match="newParty" use="#userId" />
<xsl:template match="/chatTranscript">
<html>
<header>
<xsl:value-of select="#sessionId" />
</header>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='CLIENT']">
<div class="Client" id="{#userId}">
<label>Client: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='AGENT']">
<div class="Client" id="{#userId}">
<label>Agent: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="message">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Messages,{$party-class}" id="{#eventId}">
<label>Message: <xsl:value-of select="msgText" /></label>
</div>
</xsl:template>
<xsl:template match="notice">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Notices,{$party-class}" id="{#eventId}">
<label>Notice: <xsl:value-of select="noticeText" /></label>
</div>
</xsl:template>
<xsl:template match="partyLeft">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Notices,{$party-class}" id="{#eventId}">
<label>Reason: <xsl:value-of select="reason" /></label>
</div>
</xsl:template>
<xsl:template name="lookup-class">
<xsl:variable name="party-type" select="key('party', #userId)/userInfo/#userType" />
<xsl:choose>
<xsl:when test="$party-type='CLIENT'">Client</xsl:when>
<xsl:when test="$party-type='AGENT'">Agent</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that the output is not valid HTML.

sum of previous nodes as value of current node in XSLT

I am trying to obtain the target xml such that value of a node is comma seperated values of sum of previous similar node values. For e.g:
Input:
<Items>
<Item>
<name>Drakshi</name>
<price>50</price>
</Item>
<Item>
<name>Godambi</name>
<price>30</price>
</Item>
<Item>
<name>Badami</name>
<price>70</price>
</Item>
</Items>
Output:
<result>
50,80,150
</result>
As you can see above it is 50, (50+30), (50+30+70)
I tried with for-each Item and was able to find the sum of only current node and previous selected node. Can you please guide me here
Try something like this:
<xsl:template match="Items">
<result>
<xsl:for-each select="Item">
<xsl:value-of select="sum(preceding-sibling::Item/price | price) " />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</result>
</xsl:template>
While you could use sum(preceding-sibling::...) a more efficient solution would use a recursive template to accumulate the sum one value at a time:
<xsl:template match="/Items">
<result>
<xsl:call-template name="run-total">
<xsl:with-param name="values" select="Item/price"/>
</xsl:call-template>
</result>
</xsl:template>
<xsl:template name="run-total">
<xsl:param name="values"/>
<xsl:param name="i" select="1"/>
<xsl:param name="total" select="0"/>
<xsl:variable name="balance" select="$total + $values[$i]" />
<xsl:value-of select="$balance" />
<xsl:if test="$i < count($values)">
<xsl:text>,</xsl:text>
<xsl:call-template name="run-total">
<xsl:with-param name="values" select="$values"/>
<xsl:with-param name="i" select="$i + 1"/>
<xsl:with-param name="total" select="$balance"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
If you want to solve it with XSLT 2.0 then I don't think you need any user defined function, you can write a single XPath 2.0 expression:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="Items">
<result>
<xsl:value-of
select="for $pos in 1 to count(Item)
return sum(subsequence(Item, 1, $pos)/price)"
separator=","/>
</result>
</xsl:template>
</xsl:stylesheet>
Thanks for the replies. I followed this approach which worked for me:
<xsl:function name="kk:getSumTillIndex">
<xsl:param name="index"/>
<xsl:variable name="Var_PriceArray" select="$Items/item[position()<=$index]//price/text()"/>
<xsl:for-each select="$Var_PriceArray">
<Item>
<xsl:value-of select="current()"/>
</Item>
</xsl:for-each>
</xsl:function>
<xsl:function name="kk:calulatePriceSequence">
<xsl:variable name="set" select="$Items/Item" />
<xsl:variable name="count" select="count($set)" />
<xsl:for-each select="$set">
<xsl:if test="position() <= $count">
<xsl:value-of select="sum(kk:getSumTillIndex(position()))"/>
<xsl:if test="position() < number($count)-1">
<xsl:value-of select="','" />
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:function>

XSLT with RSS feeds

I have an RSS feed that changes regularly (same format, different data) and I need to apply a transform to it to get a list of items from it using tags. The problem is, I never know what position the item with the correct tags will be in. Example: If I was generating a carousel from this for a page that is related to "theory" I'd need to pull the "items" from the list of items in the RSS that have the relevant tags, then append the class "active" to the element with the class "newsitem row item".
I realize I could do this extremely easily with jQuery -- >
$(".newsitem.row.item").first().attr("class","newsitem row item active");
But, if possible, I'd like to save a step and generate the HTML with the active class in place.
<rss xmlns:atom=" ... " version="2.0">
<channel>
<title>Latest News</title>
<link>http://...</link>
<description>Latest News</description>
<atom:link href="..." rel="self"/>
<language>en</language>
<copyright>Copyright (c) 2015</copyright>
<lastBuildDate>Sat, 25 Apr 2015 23:39:40 -0500</lastBuildDate>
<item>
<title>TITLE FOR FIRST ITEM</title>
<link>LINK FOR FIRST ITEM</link>
<description>DESCRIPTION</description>
<pubDate>Sat, 25 Apr 2015 23:39:40 -0500</pubDate>
<guid>GUID</guid>
<category>gallery</category>
<category>events</category>
<item>
<title>TITLE FOR NEXT ITEM</title>
<link>LINK FOR NEXT ITEM</link>
<description>DESCRIPTION ...</description>
<pubDate>Tue, 10 Mar 2015 20:59:12 -0500</pubDate>
<guid>GUID ...</guid>
<category>architecture</category>
<category>class acts</category>
<category>competitions</category>
<category>feature</category>
<category>global college</category>
<category>graduate work</category>
<category>health systems & design</category>
<category>honors</category>
<category>rss</category>
<category>wellness</category>
</item>
...
<item>
<title>TITLE FOR THE NTH ITEM</title>
<link>LINK FOR THE NTH ITEM</link>
<description>DESCRIPTION ...</description>
<pubDate>Tue, 10 Mar 2015 20:52:45 -0500</pubDate>
<guid>GUID ...</guid>
<category>applied creativity</category>
<category>gallery</category>
<category>coa gallery</category>
<category>graduate work</category>
<category>research</category>
<category>rss</category>
<category>technology</category>
<category>theory-philosophy</category>
<category>video</category>
<category>visualization</category>
</item>
</channel>
</rss>
My code is:
<xsl:stylesheet xmlns:xsl="..." version="1.0">
<xsl:template match="/">
<div class="row">
<div class="col-md-12 banner_image vanish">
<div class="carousel newsitems slide" data-carousel-delay="8000" id="banner-latest-85695">
<div class="carousel-inner">
<xsl:apply-templates select="//item"/>
</div>
<a class="carousel-control left" data-slide="next" href="#banner-latest-85695" title="Previous News Item"></a>
<a class="carousel-control right" data-slide="next" href="#banner-latest-85695" title="Next News Item"></a>
</div>
</div>
</div>
</xsl:template>
<xsl:template match="item|text()">
<xsl:if test="category[contains(text(),'theory')]">
<div class="newsitem row item">
<xsl:if test="position() = ?"> <!-- what position test do I use? -->
<xsl:attribute name="class">newsitem row item active</xsl:attribute>
</xsl:if>
<div class="image span">
<img>
<xsl:attribute name="src">
<xsl:value-of select="carousel"/>
</xsl:attribute>
<xsl:attribute name="alt">
<xsl:value-of select="title"/>
</xsl:attribute>
</img>
</div>
<div class="details span">
<h2>
<a>
<xsl:attribute name="href">
<xsl:value-of select="link"/>
</xsl:attribute>
<xsl:value-of select="title"/>
</a>
</h2>
<div class="publication-date">
<span>posted</span>
<xsl:value-of select="pubDate"/>
</div>
<div class="description">
<xsl:value-of select="description"/>
</div>
</div>
</div>
</xsl:if>
</xsl:template>
This works if the first item in the rss feed contains the tag I am looking for. What am I overlooking here?
** EDITED TO CLARIFY
LINKS REPLACED WITH "..."
Your question is not entirely clear. If you want to select item (or items) by the "tag" it contains, you should do something like:
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="/">
<div>
<xsl:apply-templates select="rss/channel/item[tag2]"/>
</div>
</xsl:template>
<xsl:template match="item">
<div>
<span>
<xsl:value-of select="value"/>
</span>
</div>
</xsl:template>
</xsl:stylesheet>
Here, we're looking for item/s with a child element named tag2. Applying this to the following test input:
<rss>
<channel>
<item>
<tag1/>
<value>100</value>
</item>
<item>
<tag2/>
<value>200</value>
</item>
<item>
<tag2/>
<value>201</value>
</item>
<item>
<tag3/>
<value>300</value>
</item>
</channel>
</rss>
produces the result:
<?xml version="1.0" encoding="UTF-8"?>
<div>
<div>
<span>200</span>
</div>
<div>
<span>201</span>
</div>
</div>

XSL Delimited Values for HTML Links and their Descriptions

I am trying to debug some xsl code that puts links gathered from an XML Document with their descriptions in a list, it seems to be working, except when handling multiple links gathered from a single string that are delimited with a "|" and "^" symbol.
The XML Line that contains this code is very similar to this:
<WebContent>
<content_type_desc>Links</content_type_desc>
<content_value>Google|http://www.google.com^Yahoo|http://www.yahoo.com^Bing|Http://www.bing.com</content_value>
</WebContent>
The xsl that handles this is like
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<!--Links-->
<xsl:variable name="links" select="//WebContent[content_type_desc='Links']/content_value "/>
<!--Links-->
<!--Links section-->
<xsl:if test="$links != ''">
<br />
<xsl:choose>
<xsl:when test="contains($links,'^')">
<xsl:variable name="URL" select="substring-after(substring-before($links,'^'),'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<strong>Links: </strong><br />
<xsl:value-of select="$URLText"/>
<br />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="URL" select="substring-after($links,'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<strong>Links: </strong><br />
<xsl:value-of select="$URLText"/>
<br />
</xsl:otherwise>
</xsl:choose>
<br />
</xsl:if>
<!--Links section-->
</xsl:template>
</xsl:stylesheet>
What's wrong with this is that it only outputs
<a href="http://www.google.com>Google</a>
When I would like it to output
<a href="http://www.google.com>Google</a>
<a href="http://www.yahoo.com>Yahoo</a>
<a href="http://www.bing.com>Bing</a>
Any help will be greatly appreciated as this has me completely stumped.
Assuming you are actually only using XSLT 1.0, to solve this you could make use of a named-template which is called recursively.
At the moment, the code is only processing the URL before the first ^ in the code. What you could do is put the main bulk of the code that checks the links variable in a named template. Then, in the xsl:when condition that runs when the URL does contain a ^ you add a recursive call to the named template, but passing in only the substring after the ^.
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<xsl:param name="links" select="//WebContent[content_type_desc='Links']/content_value "/>
<xsl:if test="$links != ''">
<strong>Links: </strong>
<br />
<xsl:call-template name="splitlinks">
<xsl:with-param name="links" select="$links" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="splitlinks">
<xsl:param name="links" />
<xsl:choose>
<xsl:when test="contains($links,'^')">
<xsl:variable name="URL" select="substring-after(substring-before($links,'^'),'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<xsl:value-of select="$URLText"/>
<br />
<xsl:call-template name="splitlinks">
<xsl:with-param name="links" select="substring-after($links,'^')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="URL" select="substring-after($links,'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<xsl:value-of select="$URLText"/>
<br />
</xsl:otherwise>
</xsl:choose>
<br />
</xsl:template>
</xsl:stylesheet>
Given that you have tagged your question as classic ASP your XSLT processor is likely some version of MSXML for which there is an implementation of http://www.exslt.org/str/functions/tokenize/index.html so you could use that.