-2

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>
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
user3732793
  • 1,699
  • 4
  • 24
  • 53

4 Answers4

1

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

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • thanks for the addiotional Link . Even your Xpath selection works fine for the Attribute. Unfortunatetly the output for the whole file is still giving back the wrong result fill='#f00'. I'll see what the issue is thanks – user3732793 Dec 22 '14 at 13:36
  • @user3732793 As Michael Hor says, I suspect there is a namespace in your XML that you haven't shown us. I've modified my XSLT to use the standard svg` namespace. Could you give the updated version a try? – JLRishe Dec 22 '14 at 13:42
1

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>
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
  • I wish It would work the same way for me....tried with XMLSpy how did you run it ? – user3732793 Dec 22 '14 at 13:26
  • @user3732793 See http://xsltransform.net/bFDb2C4/1. What XSLT processor are you using? The code above definitely produces the correct output, but of course we don't know how you embed this new piece into your existing stylesheet and what your actual input looks like. For instance, did you forget to mention that the SVG elements are in a namespace? – Mathias Müller Dec 22 '14 at 13:28
  • I have used XMLSpy. interesting what urls go around. see here I have added the complete svg http://xsltransform.net/bFDb2C4/2 – user3732793 Dec 22 '14 at 13:46
  • @user3732793 I was asking about the XSLT processor, not about the IDE. Anyway, I have no idea what you mean by "interesting what urls go around". Would you mind explaining that? Now you have added the actual input file - and the elements really are in the SVG namespace. The current code you're linking to fails to match the `fill`attribute. Look for elements in this namespace: http://xsltransform.net/bFDb2C4/3. – Mathias Müller Dec 22 '14 at 13:50
  • Yes that is now also what I have search for thanks ! with the Urls I meant what you and others here use to show the xsl work – user3732793 Dec 22 '14 at 13:52
  • @user3732793 Please stop switching the accepted answer - all answers are equally correct and point out where you went wrong. – Mathias Müller Dec 22 '14 at 13:55
1

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>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
0

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.

Rudramuni TP
  • 1,268
  • 2
  • 16
  • 26