首页 文章

XSLT更新只给出新值的属性和属性的XPath

提问于
浏览
2

我有一些代码比较两个XML文档的属性差异(仅更新,而不是新的属性节点),并生成一组指向属性的XPath指针和属性的新值 .

The Setup

例如,给定一个旧的XML和新的xml:

旧XML

<EntityA>
  <EntityB id="foo1" value="bar1" ignoredbutsave="bazz1"/>
</EntityA>

新的XML

<EntityA>
  <EntityB id="foo2" value="bar2"/>
</EntityA>

我的代码会返回

/EntityA/EntityB/@id, foo2
/EntityA/EntityB/@value, bar2

我想生成一个将旧XML合并到新XML中的XSLT,以创建以下XML:

<EntityA>
  <EntityB id="foo2" value="bar2" ignoredbutsave="bazz1"/>
</EntityA>

我在SO上找到的所有答案都假定了一些关于属性名称的先验知识 . 在这种情况下,我只给了XPath引用属性,而不是名称本身 . 我知道我可以解析XPath字符串以获取属性名称,但更愿意将这种复杂性保留在代码之外 .

What I've tried

我不能使用attribute value template因为我需要从旧的XML复制 ignoredbutsave 属性 . 我尝试使用xsl:param从XPath中选择属性名称并在xsl:属性中使用它,如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes"/>

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

  <xsl:template match="/EntityA/EntityB/@id">
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
       <xsl:param name="newValue" select="name(/EntityA/EntityB/@id)"/>
         <xsl:attribute name="$newValue">newAttributeId</xsl:attribute>
     </xsl:copy>
  </xsl:template>

  <xsl:template match="/EntityA/EntityB/@value">
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
       <xsl:param name="myattrname" select="name(/EntityA/EntityB/@value)"/>
         <xsl:attribute name="$myattrname">newAttributeValue</xsl:attribute>
     </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

但是,这会导致错误 The value '$myattrname' of the attribute 'name' is not a valid QName.

因此,给出一个属性的XPath和该属性的新值,如何生成一个更新该值而不显式引用属性名称的XSLT?

1 回答

  • 1

    This XSLT transformation:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output omit-xml-declaration="yes"/>
    
      <xsl:template match="node()|@*">
         <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
      </xsl:template>
    
      <xsl:template match="/EntityA/EntityB/@id">
        <xsl:attribute name="{name()}">foo2</xsl:attribute>
      </xsl:template>
    
      <xsl:template match="/EntityA/EntityB/@value">
        <xsl:attribute name="{name()}">bar2</xsl:attribute>
      </xsl:template>
    </xsl:stylesheet>
    

    Applied to your old XML:

    <EntityA>
      <EntityB id="foo1" value="bar1" ignoredbutsave="bazz1"/>
    </EntityA>
    

    Yields your old XML with the required attribute value substitutions made:

    <EntityA>
      <EntityB id="foo2" value="bar2" ignoredbutsave="bazz1"/>
    </EntityA>
    

相关问题