I have the XML source file in SVG present like this:
<svg>
<g id='a001' class='pools'>
<g id='b001' class='pool' name='Proc111'>
<g id='c001' class='lane' name='User111' PoolID='b001'>
<g id='d001' class='startevent' name='startevent111' LaneID='c001'></g>
</g>
<g id='c002' class='lane' name='User222' PoolID='b001'>
<g id='d002' class='gateway' name='gateway111' LaneID='c002'></g>
</g>
</g>
<g id='b002' class='pool' name='Proc222'>
<g id='c003' class='lane' name=' customer ' PoolID=' b002'>
<g id='d003' class='endevent' name='endevent111' LaneID='c003'> </g>
</g>
</g>
</g>
<g id='a002' class='messageflows'/>
</svg>
i wanna tranform to XML target as following document:
<process id='a001' name='proc111'>
<laneset>
<lane name='User111'/>
<lane name='User222'/>
</laneset>
<startevent id='d001' name='startevent111'/>
<gateway id='d002' name='gateway111'/>
</process>
<process id='a002' name='proc222'>
<laneset>
<lane name='customer'/>
</laneset>
<endevent id='d003' name='endevent111'/>
</process>
I had tried with some transformation but it was unsuccessfull...My solution is create the main template; and inside the main template(process template), I call for the other templates which are starteventtemplate, endeventtemplate, gateway template, etc. However, in the target document, I get all childrent which are present the same for each parent elements('process').
Because the real file is bigger than this example with a lot of elements...So, I've carried out the main problem to apply for the remaining elements.
Using the following stylesheet you can generate the desired output:
<?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:strip-space elements="*"/>
<xsl:template match="/">
<processes>
<xsl:apply-templates />
</processes>
</xsl:template>
<xsl:template match="g[#class='pool']" >
<process>
<laneset>
<xsl:apply-templates mode="laneset" />
</laneset>
<xsl:apply-templates mode="startevent" />
<xsl:apply-templates mode="gateway" />
</process>
</xsl:template>
<xsl:template match="g[#class='lane']" mode="laneset">
<lane name="{#name}"/>
</xsl:template>
<xsl:template match="g[#class='startevent']" mode="startevent">
<startevent id="{#id}" name="{#name}"/>
</xsl:template>
<xsl:template match="g[#class='gateway']" mode="gateway">
<gateway id="{#id}" name="{#name}"/>
</xsl:template>
</xsl:stylesheet>
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="g[#class='pools']">
<processes>
<xsl:apply-templates />
</processes>
</xsl:template>
<xsl:template match="g[#class='pool']" priority="1">
<process id="{#id}" name="{#name}">
<laneset>
<xsl:apply-templates/>
</laneset>
<xsl:apply-templates select="*/*"/>
</process>
</xsl:template>
<xsl:template match="g/g">
<xsl:element name="{#class}">
<xsl:copy-of select="#id[../#class != 'lane']|#name"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<processes>
<process id="b001" name="Proc111">
<laneset>
<lane name="User111" />
<lane name="User222" />
</laneset>
<startevent id="d001" name="startevent111" />
<gateway id="d002" name="gateway111" />
</process>
<process id="b002" name="Proc222">
<laneset>
<lane name=" customer " />
</laneset>
<endevent id="d003" name="endevent111" />
</process>
</processes>
EDIT: compacting code.
Related
there is that XML Node
<svg>
<g transform="translate(113.63-359.13)">
<use fill="#f00" xlink:href="#D"/>
<g transform="translate(72.59-8.504)">
<use xlink:href="#E"/>
<path fill="#f00" stroke="#000" stroke-linejoin="round" stroke-linecap="round" stroke-width=".24" d="m6.04 526.26h19.843v4.961h-19.843z"/>
<use xlink:href="#F"/>
</g>
<text x="20.41" y="527.6" fill="#000" font-family="Arial" font-size="8">ProcessOutbound</text>
</g>
</svg>
which can be found by this Xpath
/svg/g[text="ProcessOutbound"]/use
also this work fine
/svg/g[text="ProcessOutbound"]/use/#fill
but for some reasons that xsl is not replaceing #f00 with #00f which is what have tired
<?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" encoding="UTF-8"/>
<xsl:param name="blue" select="'#00f'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match='/svg/g[text="ProcessOutbound"]/use'>
<xsl:attribute name='fill'>
<xsl:value-of select="'$blue'"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
actually the whole svg file is copied but the fill attribute is not replaced. I tried to achive a copy but with the replaced fill value
What is the correct way to replace attribut values with constant values by xsl ?
So the expected result should look like
<g transform="translate(113.63-359.13)">
<use fill="#00f" xlink:href="#D"/>
<g transform="translate(72.59-8.504)">
<use xlink:href="#E"/>
<path fill="#f00" stroke="#000" stroke-linejoin="round" stroke-linecap="round" stroke-width=".24" d="m6.04 526.26h19.843v4.961h-19.843z"/>
<use xlink:href="#F"/>
</g>
<text x="20.41" y="527.6" fill="#000" font-family="Arial" font-size="8">ProcessOutbound</text>
</g>
There are a few things incorrect with your XSLT:
It is trying to replace the whole 'use' element with an attribute.
You are using two pairs of quotes around $blue, which causes it to be treated as a string.
You are not using namespaces even though your XML uses a namespace.
Please try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:param name="blue" select="'#00f'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match='svg:g[svg:text = "ProcessOutbound"]/svg:use/#fill'>
<xsl:attribute name='fill'>
<xsl:value-of select="$blue"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
When run on your sample input, the result is:
<svg xmlns:xlink="...">
<g transform="translate(113.63-359.13)">
<use xlink:href="#D" fill="#00f" />
<g transform="translate(72.59-8.504)">
<use xlink:href="#E" xmlns:xlink="x" />
<path fill="#f00" d="m6.04 526.26h19.843v4.961h-19.843z" stroke-width=".24" stroke-linecap="round" stroke-linejoin="round" stroke="#000" />
<use xlink:href="#F" />
</g>
<text font-family="Arial" fill="#000" font-size="8" y="527.6" x="20.41">ProcessOutbound</text>
</g>
</svg>
http://www.xsltcake.com/slices/d8pdoi
If I am guessing correctly and your input is a valid SVG document, then all its elements are in the SVG namespace. IOW, your input example should actually look like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(113.63-359.13)">
<use fill="#f00" xlink:href="#D"/>
<g transform="translate(72.59-8.504)">
<use xlink:href="#E"/>
<path fill="#f00" stroke="#000" stroke-linejoin="round" stroke-linecap="round" stroke-width=".24" d="m6.04 526.26h19.843v4.961h-19.843z"/>
<use xlink:href="#F"/>
</g>
<text x="20.41" y="527.6" fill="#000" font-family="Arial" font-size="8">ProcessOutbound</text>
</g>
</svg>
And then your XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="blue" select="'#00f'"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="svg:g[svg:text='ProcessOutbound']/svg:use/#fill">
<xsl:attribute name='fill'>
<xsl:value-of select="$blue"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Assuming a well-formed input (the prefix xlink: is not bound because you did not include its namespace definition), use the stylesheet below.
Rather than matching the element use, directly match the node you'd like to modify, the fill attribute of use.
Stylesheet
Your question suggests that the second template should actually match /svg/g[8]/use/#fill if I understood correctly.
<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="blue" select="'#00f'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/svg/g/use/#fill">
<xsl:attribute name="fill">
<xsl:value-of select="$blue"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
XML Output
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(113.63-359.13)">
<use fill="#00f" xlink:href="#D"/>
<g transform="translate(72.59-8.504)">
<use xlink:href="#E"/>
<path fill="#f00" stroke="#000" stroke-linejoin="round" stroke-linecap="round" stroke-width=".24" d="m6.04 526.26h19.843v4.961h-19.843z"/>
<use xlink:href="#F"/>
</g>
<text x="20.41" y="527.6" fill="#000" font-family="Arial" font-size="8">ProcessOutbound</text>
</g>
</svg>
EDIT: As mentioned in a comment, try the following stylesheet if your SVG elements actually are in a namespace:
Stylesheet
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="blue" select="'#00f'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/svg:svg/svg:g/svg:use/#fill">
<xsl:attribute name="fill">
<xsl:value-of select="$blue"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Try with this,
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:param name="blue" select="'#00f'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/svg/g[contains(text, 'ProcessOutbound')]/use">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name='fill'>
<xsl:value-of select="$blue"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If this not meeting u r requirement, provide u r simple required text.
I am completely new to xslt. Please help me to write style sheet.I have input xml like this
Input XML:
<elements>
<e1>
<pid>1</pid>
<cid>2</cid>
</e1>
<e1>
<pid>1</pid>
<cid>3</cid>
</e1>
<e1>
<pid>2</pid>
<cid>4</cid>
</e1>
</elements>
Desired XML:
<tree>
<unit id="1">
<unit id="2">
<unit id="4">
<data></data>
</unit>
<data></data>
</unit>
<unit id="3">
<data></data>
</unit>
<data></data>
</unit>
</tree>
I feel this should be really easy but I'm struggling to find information about how to do this. My XSLT knowledge isn't great.
I'm not 100% sure how you want the XSLT to determine from that input that the top id is 1 (is it because it's the only pid value with no corresponding cid values, or is it always 1?). Nonetheless, this should do the job:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kItemsByC" match="e1" use="cid" />
<xsl:key name="kItemsByP" match="e1" use="pid" />
<xsl:template match="/">
<tree>
<xsl:call-template name="Unit">
<!-- This will be the value of the <pid> that has no <cid> references to
it (assuming there is only one top-level <pid>) -->
<xsl:with-param name="id"
select="string(/elements/e1/pid[not(key('kItemsByC', .))])" />
</xsl:call-template>
</tree>
</xsl:template>
<xsl:template match="e1" name="Unit">
<xsl:param name="id" select="cid" />
<unit id="{$id}">
<xsl:apply-templates select="key('kItemsByP', $id)" />
<data />
</unit>
</xsl:template>
</xsl:stylesheet>
When this is run on your sample input, this produces:
<tree>
<unit id="1">
<unit id="2">
<unit id="4">
<data />
</unit>
<data />
</unit>
<unit id="3">
<data />
</unit>
<data />
</unit>
</tree>
Note: The above XSLT has logic to attempt to dynamically locate the top-level ID. If it can be assumed that the top-level unit will always have ID 1, then one key and the above XSLT's (somewhat) complicated formula can be eliminated:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kItemsByP" match="e1" use="pid" />
<xsl:template match="/">
<tree>
<xsl:call-template name="Unit">
<xsl:with-param name="id" select="1" />
</xsl:call-template>
</tree>
</xsl:template>
<xsl:template match="e1" name="Unit">
<xsl:param name="id" select="cid" />
<unit id="{$id}">
<xsl:apply-templates select="key('kItemsByP', $id)" />
<data />
</unit>
</xsl:template>
</xsl:stylesheet>
This also produces the requested output when run on your sample input.
Ah, after reading JLRishe I think I get it: "pid" means "parent ID", "cid" means "child ID", and e1 represents a parent-child relationship. Brilliant detective work, I would never have worked that out for myself.
The basic model is that when you are positioned on a parent element you do apply-templates to its children. This applies just as well if the parent/child relationships are represented by primary/foreign keys as when they are represented using the XML hierarchy. So the essence is:
<xsl:template match="e1">
<unit id="{pid}">
<xsl:apply-templates select="//e1[pid=current()/cid]"/>
<data/>
</unit>
</xsl:template>
which is essentially JLRishe's solution except he has added an optimization using keys.
Given siblings, some of which are <row> elements and some not, like this,
<h />
<row id='v' />
<a />
<b />
<row id='w' />
<d />
<row id='x' />
<row id='y' />
<f />
<r />
<row id='z' />
using xslt 1.0, I need to process them in order but to group the non-row ones together as I go, like this,
<notRow>
<h />
</notRow>
<row id='v' />
<notRow>
<a />
<b />
</notRow>
<row id='w' />
<notRow>
<d />
<row id='x' />
<row id='y' />
<notRow>
<f />
<r />
</notRow>
<row id='z' />
The first and last may or may not be <row> elements.
How?
It can be as short and simple as this (no need of calling templates several times, xsl:for-each, xsl:if). Here is the complete 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:key name="kFollowing" match="*/*[not(self::row)]"
use="concat(generate-id(..), '+',
generate-id(preceding-sibling::row[1])
)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template priority="2" match=
"*/*[not(self::row)
and
(preceding-sibling::*[1][self::row]
or not(preceding-sibling::*)
)]">
<notRow>
<xsl:copy-of select=
"key('kFollowing', concat(generate-id(..), '+',
generate-id(preceding-sibling::row[1])
))"/>
</notRow>
</xsl:template>
<xsl:template match="*/*[not(self::row)]"/>
</xsl:stylesheet>
When this transformation is applied on the provided XML (wrapped into a single top element to make it well-formed):
<t>
<h />
<row id='v' />
<a />
<b />
<row id='w' />
<d />
<row id='x' />
<row id='y' />
<f />
<r />
<row id='z' />
</t>
the wanted, correct result is produced:
<t>
<notRow>
<h/>
</notRow>
<row id="v"/>
<notRow>
<a/>
<b/>
</notRow>
<row id="w"/>
<notRow>
<d/>
</notRow>
<row id="x"/>
<row id="y"/>
<notRow>
<f/>
<r/>
</notRow>
<row id="z"/>
</t>
Update:
The OP has expressed an additional requirement that nodes need be processed by matching templates -- not just copied.
This requires only minimal change:
<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:key name="kFollowing" match="*/*[not(self::row)]"
use="concat(generate-id(..), '+',
generate-id(preceding-sibling::row[1])
)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template priority="2" match=
"*/*[not(self::row)
and
(preceding-sibling::*[1][self::row]
or not(preceding-sibling::*)
)]">
<notRow>
<xsl:apply-templates mode="group" select=
"key('kFollowing', concat(generate-id(..), '+',
generate-id(preceding-sibling::row[1])
))"/>
</notRow>
</xsl:template>
<!-- This template can be replaced with whatever processing needed -->
<xsl:template match="*" mode="group">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="*/*[not(self::row)]"/>
</xsl:stylesheet>
The template that operates in mode "group" should be substituted with template(s) that implement the exact wanted processing. In this case it copies the matched element -- but in the real application any wanted processing would go here.
You might be able to do a trick with a key to group each non-row element by its preceding row (if there is one), or its parent element if not:
<xsl:key name="elementsFollowingRow"
match="*[not(self::row)]"
use="generate-id( (.. | preceding-sibling::row )[last()])" />
and define a named template to put in a notRow if the current element has any associated elements according to the key
<xsl:template name="addNotRow">
<xsl:if test="key('elementsFollowingRow', generate-id())">
<notRow>
<xsl:copy-of select="key('elementsFollowingRow', generate-id())" />
</notRow>
</xsl:if>
</xsl:template>
Then in the template where you're matching the parent element (the one that contains all these row and non-row elements you can do
<xsl:call-template name="addNotRow" />
<xsl:for-each select="row">
<xsl:copy-of select="." />
<xsl:call-template name="addNotRow" />
</xsl:for-each>
The first call-template outside the for-each will deal with any notRow that is required before the first row, and the call inside the for-each will put in any notRow required after the row in question.
This isn't pretty, but it works.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="t">
<xsl:if test="row[1]/preceding-sibling::*">
<notRow>
<xsl:for-each select="row[1]/preceding-sibling::*" >
<xsl:copy />
</xsl:for-each>
</notRow>
</xsl:if>
<xsl:for-each select="row">
<xsl:copy-of select="."/>
<xsl:if test="following-sibling::row[1]/preceding-sibling::*[generate-id(preceding-sibling::row[1])=generate-id(current())]">
<notRow>
<xsl:for-each select="following-sibling::row[1]/preceding-sibling::*[generate-id(preceding-sibling::row[1])=generate-id(current())]">
<xsl:copy />
</xsl:for-each>
</notRow>
</xsl:if>
</xsl:for-each>
<xsl:if test="row[last()]/following-sibling::*">
<notRow>
<xsl:for-each select="row[last()]/following-sibling::*" >
<xsl:copy />
</xsl:for-each>
</notRow>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
On this XML source
<t>
<h />
<i />
<row id='v' />
<a />
<b />
<row id='w' />
<d />
<row id='x' />
<row id='y' />
<f />
<r />
<row id='z' />
<i />
</t>
it returns the correct result:
<notRow>
<h/>
<i/>
</notRow>
<row id="v"/>
<notRow>
<a/>
<b/>
</notRow>
<row id="w"/>
<notRow>
<d/>
</notRow>
<row id="x"/>
<row id="y"/>
<notRow>
<f/>
<r/>
</notRow>
<row id="z"/>
<notRow>
<i/>
</notRow>
but it does seem there should be something simpler.
I have some XSLT that replaces linebreaks with <Break/> tags and it works fine as long as there isn't multiple consecutive linebreaks. I think it's the indent="yes" that's causing problems.
Can it be disabled for some nodes?
Basically nodes with mixed content (text and elements) can not contain any linebreaks.
The input xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Account xmlns="http://example.com/account">
<Owner>
<ID>012345789</ID>
<Name>Peter Johnson</Name>
</Owner>
<Notes>
<NoteID>012345789</NoteID>
<Text>This is the description:
Line 1
Line 2
Line 3
Line 4, after double linebreak
Line 5</Text>
</Notes>
</Account>
The XSL:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://example.com/account" version="1.0">
<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes"/>
<xsl:template name="replace_sab">
<!-- with string s, replace substring a by string b -->
<!-- s, a and b are parameters determined upon calling -->
<xsl:param name="s" />
<xsl:param name="a" />
<xsl:param name="b" />
<xsl:choose>
<xsl:when test="contains($s,$a)">
<xsl:value-of select="substring-before($s,$a)" />
<xsl:copy-of select="$b" />
<xsl:call-template name="replace_sab">
<xsl:with-param name="s" select="substring-after($s,$a)" />
<xsl:with-param name="a" select="$a" />
<xsl:with-param name="b" select="$b" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$s" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[not(normalize-space())]"/>
<xsl:template match="text()[boolean(normalize-space())]">
<xsl:call-template name="replace_sab">
<xsl:with-param name="s" select="." />
<xsl:with-param name="a" select="'
'" />
<xsl:with-param name="b"><Break/></xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
The output that I get:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Account xmlns="http://example.com/account">
<Owner>
<ID>012345789</ID>
<Name>Peter Johnson</Name>
</Owner>
<Notes>
<NoteID>012345789</NoteID>
<Text>This is the description:<Break/>Line 1<Break/>Line 2<Break/>Line 3<Break/>
<Break/>Line 4, after double linebreak<Break/>Line 5</Text>
</Notes>
</Account>
The output I would like:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Account xmlns="http://example.com/account">
<Owner>
<ID>012345789</ID>
<Name>Peter Johnson</Name>
</Owner>
<Notes>
<NoteID>012345789</NoteID>
<Text>This is the description:<Break/>Line 1<Break/>Line 2<Break/>Line 3<Break/><Break/>Line 4, after double linebreak<Break/>Line 5</Text>
</Notes>
</Account>
I am using "TIBCO XSLT 1.0" XSLT engine in a Tibco BusinessWorks process.
There's no standard way of doing this.
If you were using Saxon you could use the saxon:suppress-indentation output parameter, which becomes a standard option in XSLT 3.0.
Perhaps you could find a way of inserting the Saxon serializer into your processing pipeline even if you stick with the Tibco XSLT engine.
My source document is:
<?xml version="1.0" encoding="UTF8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:fn="http://www.w3.org/2005/xpathfunctions" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance" xsi:schemaLocation="http://schema.omg.org/spec/BPMN/2.0 schema\BPMN20.xsd" targetNamespace="http://schema.omg.org/spec/BPMN/2.0">
<process id="DA444C7EB7A92BC0EC615091EFE52E9F" name="Process111">
<laneSet>
<lane id="BE805267E22661E25210E901418B7DA2" name="Lane111" >
<flowNodeRefs>E705CE86B8897B266BA6AC81E2F1A5BC</flowNodeRefs>
<flowNodeRefs>643E3A26322BEECB2DBD84BF2A6F9CA5</flowNodeRefs>
</lane>
<lane id="2F92C8B27CE52AFDB382D4EAC634E634" name="Lane222" >
<flowNodeRefs>A65A0630689FA02F3BBB6AC27D906603</flowNodeRefs>
<flowNodeRefs>DDA49A7836C13B7DC3208778C4B03526</flowNodeRefs>
</lane>
</laneSet>
<startEvent id="E705CE86B8897B266BA6AC81E2F1A5BC" name="Start111" />
<endEvent id="643E3A26322BEECB2DBD84BF2A6F9CA5" name="End111" />
<startEvent id="A65A0630689FA02F3BBB6AC27D906603" name="Start222" />
<terminateEvent id="DDA49A7836C13B7DC3208778C4B03526" name="Terminate111" />
</process>
<process id="A7F84E7EA73F9436DCB925D5C3208227" name="Process2222">
<laneSet>
<lane id="B8EE1D7AA494C6D25656434F1CAF803F" name="Lane444" />
</laneSet>
</process>
</definitions>
I want to tranform to the target document:
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns.x="org.w3c.dom.svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<g id="BPMNDIAGRAM" transform="scale(1)">
<g id="POOLS" class="POOLS">
<g id="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F" class="POOL" >
<g >
<text >
<tspan >Process111</tspan>
</text>
</g>
<g id="BE805267-E226-61E2-5210-E901418B7DA2" class="LANE" PoolID="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F">
<g>
<text >
<tspan>Lane111</tspan>
</text>
</g>
<g id="EVENTS_BE805267-E226-61E2-5210-E901418B7DA2" class="EVENTS">
<g id="643E3A26-322B-EECB-2DBD-84BF2A6F9CA5" class="ENDEVENT" LaneID="BE805267-E226-61E2-5210-E901418B7DA2">
<text >
<tspan >End111</tspan>
</text>
</g>
<g id="E705CE86-B889-7B26-6BA6-AC81E2F1A5BC" class="STARTEVENT" LaneID="BE805267-E226-61E2-5210-E901418B7DA2">
<text >
<tspan x="0" dy="10">Start111</tspan>
</text>
</g>
</g>
</g>
<g id="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634" class="LANE" PoolID="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F">
<g >
<text >
<tspan x="0" dy="10">Lane222</tspan>
</text>
</g>
<g id="EVENTS_2F92C8B2-7CE5-2AFD-B382-D4EAC634E634" class="EVENTS">
<g id="A65A0630689FA02F3BBB6AC27D906603" class="STARTEVENT" LaneID="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634">
<text >
<tspan x="0" dy="10">Start222</tspan>
</text>
</g>
<g id="DDA49A78-36C1-3B7D-C320-8778C4B03526" class="TERMINATEEVENT" LaneID="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634">
<text >
<tspan x="0" dy="10">Terminate111</tspan>
</text>
</g>
</g>
</g>
</g>
<g id="A7F84E7E-A73F-9436-DCB9-25D5C3208227" class="POOL" >
<g >
<text >
<tspan >Process2222</tspan>
</text>
</g>
<g id="B8EE1D7A-A494-C6D2-5656-434F1CAF803F" class="LANE" PoolID="A7F84E7E-A73F-9436-DCB9-25D5C3208227">
<g >
<text >
<tspan>Lane444</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
</svg>
And my transformation file is as following code:
<?xml version="1.0" encoding="Windows-1252"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- BPMN 2.0 Transformation: BPMN2.0 xml-to-SVG xml -->
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<svg>
<xsl:attribute name="xmlns.x">org.w3c.dom.svg</xsl:attribute>
<xsl:attribute name="targetNamespace">http://schema.omg.org/spec/BPMN/2.0</xsl:attribute>
<xsl:call-template name="rootElementTemplate"/>
</svg>
</xsl:template>
<!-- rootElementTemplate -->
<xsl:template name="rootElementTemplate">
<g>
<!--call the other templates-->
<xsl:call-template name="pools"/>
</g>
</xsl:template>
<xsl:template name="pools">
<g>
<xsl:attribute name="id">POOLS</xsl:attribute>
<xsl:attribute name="class">POOLS</xsl:attribute>
<xsl:apply-templates select="process"/>
</g>
</xsl:template>
<xsl:template match="process">
<g>
<xsl:attribute name="id"><xsl:value-of select="."/></xsl:attribute>
<xsl:attribute name="class">POOL</xsl:attribute>
<xsl:call-template name="text1"/>
</g>
</xsl:template>
<xsl:template name="text1" >
<xsl:for-each select="#name">
<g >
<xsl:element name="text">
<xsl:element name="tspan"><xsl:value-of select= "."/></xsl:element>
</xsl:element>
</g>
</xsl:for-each>
</xsl:template>
<xsl:template match="lane">
<g id="{#id}" class="LANE" >
<xsl:apply-templates select="#name"/>
<xsl:variable name="p" select="count(preceding-sibling::lane)+1"/>
<xsl:variable name="ref" select="ancestor::process/*[$p+1]"/>
<xsl:apply-templates select="$ref"/>
</g>
</xsl:template>
<xsl:template match="startevent">
<g id="{#id}" class="STARTEVENT" name="{#name}" />
</xsl:template>
</xsl:stylesheet>
I don't know why it doesn't work? Please help me
This stylesheet:
<xsl:stylesheet version="1.0"
exclude-result-prefixes="m"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:x="org.w3c.dom.svg">
<xsl:variable name="attrSet">
<dummy x="0" dy="10"/>
</xsl:variable>
<xsl:template match="m:definitions">
<svg version="1.1">
<g id="BPMNDIAGRAM" transform="scale(1)">
<g id="POOLS" class="POOLS">
<xsl:apply-templates />
</g>
</g>
</svg>
</xsl:template>
<xsl:template match="m:process">
<g class="POOL">
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="#name|m:laneSet/*"/>
</g>
</xsl:template>
<xsl:template match="*">
<xsl:param name="idName" select="'PoolID'"/>
<xsl:param name="id" select="../../#id"/>
<g class="{translate(name(),
'lanedvtsrmi',
'LANEDVTSRMI')}">
<xsl:attribute name="{$idName}">
<xsl:apply-templates select="$id" mode="id"/>
</xsl:attribute>
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="#name"/>
<xsl:apply-templates/>
</g>
</xsl:template>
<xsl:template match="m:flowNodeRefs[position()!=1]"/>
<xsl:template match="m:flowNodeRefs[1]">
<g class="EVENTS">
<xsl:attribute name="id">
<xsl:text>EVENTS_</xsl:text>
<xsl:apply-templates select="../#id" mode="id"/>
</xsl:attribute>
<xsl:apply-templates select="../../../*[#id = current()/../*]">
<xsl:with-param name="idName" select="'LaneID'"/>
<xsl:with-param name="id" select="../#id"/>
</xsl:apply-templates>
</g>
</xsl:template>
<xsl:template match="#id">
<xsl:attribute name="id">
<xsl:apply-templates select="." mode="id"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#id" mode="id">
<xsl:value-of select="concat(substring(.,1,8),'-',
substring(.,9,4),'-',
substring(.,13,4),'-',
substring(.,17,4),'-',
substring(.,21))"/>
</xsl:template>
<xsl:template match="#name">
<g>
<text>
<tspan>
<xsl:copy-of select="document('')/*/xsl:variable
[#name='attrSet']/*/#*
[not(current()/../self::m:endEvent|
current()/../self::m:process)]
[not(generate-id(current()/..) =
generate-id(current()/../../m:lane[1]))]"/>
<xsl:value-of select="."/>
</tspan>
</text>
</g>
</xsl:template>
</xsl:stylesheet>
Output:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:x="org.w3c.dom.svg">
<g id="BPMNDIAGRAM" transform="scale(1)">
<g id="POOLS" class="POOLS">
<g class="POOL" id="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F">
<g>
<text>
<tspan>Process111</tspan>
</text>
</g>
<g class="LANE" PoolID="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F" id="BE805267-E226-61E2-5210-E901418B7DA2">
<g>
<text>
<tspan>Lane111</tspan>
</text>
</g>
<g class="EVENTS" id="EVENTS_BE805267-E226-61E2-5210-E901418B7DA2">
<g class="STARTEVENT" LaneID="BE805267-E226-61E2-5210-E901418B7DA2" id="E705CE86-B889-7B26-6BA6-AC81E2F1A5BC">
<g>
<text>
<tspan x="0" dy="10">Start111</tspan>
</text>
</g>
</g>
<g class="ENDEVENT" LaneID="BE805267-E226-61E2-5210-E901418B7DA2" id="643E3A26-322B-EECB-2DBD-84BF2A6F9CA5">
<g>
<text>
<tspan>End111</tspan>
</text>
</g>
</g>
</g>
</g>
<g class="LANE" PoolID="DA444C7E-B7A9-2BC0-EC61-5091EFE52E9F" id="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634">
<g>
<text>
<tspan x="0" dy="10">Lane222</tspan>
</text>
</g>
<g class="EVENTS" id="EVENTS_2F92C8B2-7CE5-2AFD-B382-D4EAC634E634">
<g class="STARTEVENT" LaneID="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634" id="A65A0630-689F-A02F-3BBB-6AC27D906603">
<g>
<text>
<tspan x="0" dy="10">Start222</tspan>
</text>
</g>
</g>
<g class="TERMINATEEVENT" LaneID="2F92C8B2-7CE5-2AFD-B382-D4EAC634E634" id="DDA49A78-36C1-3B7D-C320-8778C4B03526">
<g>
<text>
<tspan x="0" dy="10">Terminate111</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
<g class="POOL" id="A7F84E7E-A73F-9436-DCB9-25D5C3208227">
<g>
<text>
<tspan>Process2222</tspan>
</text>
</g>
<g class="LANE" PoolID="A7F84E7E-A73F-9436-DCB9-25D5C3208227" id="B8EE1D7A-A494-C6D2-5656-434F1CAF803F">
<g>
<text>
<tspan>Lane444</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
</svg>
Note: These lines
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="#name|m:laneSet/*"/>
And
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="#name"/>
<xsl:apply-templates/>
Could be like
<xsl:apply-templates select="#*|m:laneSet/*"/>
And
<xsl:apply-templates select="#*|*"/>
But, there is no guarantee from the spec that attributes are proccess in any order (beside that before child elements).
Also, I use a tricky way for add x and dy attributes. But the conditions in predicates could be use as test for a xsl:if, adding these attributes with xsl:attribute.