【问题标题】:Replace xml attribute values with constant values by xsl通过 xsl 将 xml 属性值替换为常量值
【发布时间】:2015-02-20 13:02:52
【问题描述】:

有那个 XML 节点

<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>

可以通过这个 Xpath 找到

/svg/g[text="ProcessOutbound"]/use

这个工作也很好

/svg/g[text="ProcessOutbound"]/use/@fill

但由于某些原因,xsl 没有用 #00f 替换 #f00,这已经很累了

<?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>

实际上整个 svg 文件被复制了,但填充属性没有被替换。我试图获得一个副本,但使用替换的填充值

xsl用常量值替换属性值的正确方法是什么?

所以预期的结果应该是这样的

   <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>

【问题讨论】:

  • 您的 XML 无效。请尝试发布完整的 XML。而且,在您显示的 XML 片段中,我找不到 /svg/g[text="ProcessOutbound"]/use 的匹配项
  • 完整显示您所需的文本。 是根元素吗?如果是的话,改变它。我观察到,XML 文件中的某些属性带有大括号“(”,我假设属性中不允许大括号。
  • 文件有点大,很难在这里发布完整的文件。完整的 xpath 将是 /svg/g[8]/use/@fill
  • 我不是在询问整个 XML,对于您给定的输入,预期的结果可能是什么。
  • 现在以这种方式编辑了帖子。这只是fill的值

标签: xslt xpath svg xslt-1.0


【解决方案1】:

您的 XSLT 有几处不正确:

  • 它正在尝试用一个属性替换整个“使用”元素。
  • 您在 $blue 周围使用了两对引号,这导致它被视为字符串。
  • 即使您的 XML 使用命名空间,您也没有使用命名空间。

请试试这个:

<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>

在您的示例输入上运行时,结果是:

<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

【讨论】:

  • 感谢额外的链接。甚至您的 Xpath 选择也适用于 Attribute。不幸的是,整个文件的输出仍然返回错误的结果 fill='#f00'。我看看是什么问题谢谢
  • @user3732793 正如 Michael Hor 所说,我怀疑您的 XML 中存在一个您没有向我们展示的命名空间。我已经修改了我的 XSLT 以使用标准的 svg` 命名空间。可以试试更新的版本吗?
【解决方案2】:

如果我猜对了并且您的输入是一个有效的 SVG 文档,那么它的所有元素都在 SVG 命名空间中。 IOW,您的输入示例实际上应该如下所示:

<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>

然后是你的 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>

【讨论】:

  • @user3732793 那么为什么这不是公认的答案呢?
  • 是的,这是正确的答案 - 但 JLRishe 和我的也是如此。但我不介意谁的答案被接受。
  • @MathiasMüller 我也不介意。不过,我认为将正确答案放在顶部会很有帮助。至于其他答案是否正确……啊,我知道他们是现在。 :-)
【解决方案3】:

假设输入格式正确(前缀 xlink: 未绑定,因为您没有包含其命名空间定义),请使用下面的样式表。

不匹配元素use,直接匹配你要修改的节点,usefill属性。

样式表

如果我理解正确,您的问题表明第二个模板实际上应该匹配 /svg/g[8]/use/@fill

<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 输出

<?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>

编辑:如评论中所述,如果您的 SVG 元素实际上位于命名空间中,请尝试以下样式表:

样式表

<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>

【讨论】:

  • 我希望它能以同样的方式为我工作....用 XMLSpy 试过你是如何运行它的?
  • @user3732793 见xsltransform.net/bFDb2C4/1。您使用的是什么 XSLT 处理器?上面的代码肯定会产生正确的输出,但是我们当然不知道您如何将这个新部分嵌入到现有样式表中以及您的实际输入是什么样的。例如,您是否忘记提及 SVG 元素位于命名空间中?
  • 我使用过 XMLSpy。有趣的网址是什么。看到这里我已经添加了完整的 svg xsltransform.net/bFDb2C4/2
  • @user3732793 我问的是 XSLT 处理器,而不是 IDE。无论如何,我不知道您所说的“有趣的网址是什么”。你介意解释一下吗?现在您已经添加了实际的输入文件 - 元素确实位于 SVG 命名空间中。您链接到的当前代码与fillattribute 不匹配。在此命名空间中查找元素:xsltransform.net/bFDb2C4/3.
  • 是的,这也是我现在正在寻找的,谢谢!我的意思是你和这里的其他人用来展示 xsl 作品的网址
【解决方案4】:

试试这个,

<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>

如果这不符合您的要求,请提供您所需的简单文本。

【讨论】:

  • 对不起,这不起作用。我仍然有 f00 而不是 00f 作为输出中的值
猜你喜欢
  • 1970-01-01
  • 2012-11-15
  • 2016-10-27
  • 2017-12-05
  • 1970-01-01
  • 2018-04-19
  • 2016-03-13
  • 1970-01-01
  • 2015-03-15
相关资源
最近更新 更多