XSLT复制XML文档并在特定条件下添加属性和生成的值

时间:2010-10-27 13:30:14

标签: xml xslt

我对XSLT很陌生并且有一个迫切的工作要求,我发现要解决这个问题非常复杂。

我有一个XML文档,需要在特定条件下添加属性。

XML文档非常简单:

<A x="foo" y="bar" z="">
<B/>
<C/></A>

基本上,如果存在属性“z”。然后需要将新属性添加到节点“A”。属性的值必须是在某些位置替换值为“x”和“y”的文本字符串。结果应如下所示:

<A x="foo" y="bar" z="" new="values present are x=foo and y=bar">
<B/>
<C/></A>

我已经创建了一个将文档复制到属性级别的XSLT。但是在尝试创建测试属性z的逻辑并创建基于x和y的字符串时,我遇到了绊脚石。

有人可以帮忙吗?

由于

另外 - 如果我的代码格式糟透了,请道歉

来自评论:

  

有些事情正在停止   这些解决方案有效文本XML   我上面实际上有一个根   包含所有内容的节点<R>。 R   node有一个这样的属性:   xmlns="http://www.fixprotocol.org/FIXML-4-4"。   出于某种原因添加此属性   导致模板匹配“A”   不行吗?!

3 个答案:

答案 0 :(得分:3)

已更新:OP已解释(仅在评论中注释!):

  

有些事情正在停止   这些解决方案有效文本XML   我上面实际上有一个根   包含它的节点。 <R>   node有一个这样的属性:   xmlns="http://www.fixprotocol.org/FIXML-4-4"。   出于某种原因添加此属性   导致模板匹配“A”   不行吗?!

这可能是最短的

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.fixprotocol.org/FIXML-4-4"
 xmlns="http://www.fixprotocol.org/FIXML-4-4" exclude-result-prefixes="x">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="x:A[@z]">
  <A new="values present are x={@x} and y={@y}">
   <xsl:apply-templates select="node()|@*"/>
  </A>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
    <A x="foo" y="bar" z="">
        <B/>
        <C/>
    </A>
</R>

产生了想要的正确结果

<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
    <A new="values present are x=foo and y=bar" x="foo" y="bar" z="">
        <B></B>
        <C></C>
    </A>
</R>

答案 1 :(得分:1)

您可以使用以下XSLT:

<?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:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="A">
    <A>
      <xsl:if test="@z">
        <xsl:attribute name="new">
         <xsl:value-of select="concat('values present are x=',@x,' and y=',@y)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates select="@* | node()"/>
    </A>

  </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:1)

编辑:现在使用正确的命名空间。

此样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:fixml="http://www.fixprotocol.org/FIXML-4-4">
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="fixml:A/@z">
        <xsl:call-template name="identity"/>
        <xsl:attribute name="new">
            <xsl:value-of
               select="concat('values present are x=',../@x,' and y=',../@y)"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

使用此输入:

<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
    <A x="foo" y="bar" z="">
        <B/>
        <C/>
    </A>
</R>

输出:

<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
    <A x="foo" y="bar" z="" new="values present are x=foo and y=bar">
        <B></B>
        <C></C>
    </A>
</R>