2

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

设置

例如,给定一个旧的 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 字符串以派生属性名称,但更愿意将这种复杂性排除在代码之外。

我试过的

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

<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 来更新该值而不显式引用属性名称?

4

1 回答 1

1

这个 XSLT 转换:

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

应用于您的旧 XML:

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

使用所需的属性值替换生成旧 XML:

<EntityA>
  <EntityB id="foo2" value="bar2" ignoredbutsave="bazz1"/>
</EntityA>
于 2013-10-24T23:50:37.117 回答