Replace xml attribute values with constant values

2019-09-23 02:11发布

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>

4条回答
爷的心禁止访问
2楼-- · 2019-09-23 02:15

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.

查看更多
别忘想泡老子
3楼-- · 2019-09-23 02:18

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

查看更多
虎瘦雄心在
4楼-- · 2019-09-23 02:19

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>
查看更多
【Aperson】
5楼-- · 2019-09-23 02:34

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>
查看更多
登录 后发表回答