XSLT基于子节点值替换匹配的元素

时间:2016-10-07 18:22:40

标签: xslt xslt-2.0

我有以下源XML文档:

<UserDefinedFields>
  <UserDefinedField>
    <Name>ABC</Name>
    <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
    <Name>XYZ</Name>
    <Value>645q3245</Value>
  </UserDefinedField>
</UserDefinedFields>

如果存在匹配的<Name>值,我想覆盖输入XML中的匹配节点。换句话说,合并它的最终结果是:

<UserDefinedField>
  <Name>XYZ</Name>
  <Value>NEWVALUE!</Value>
</UserDefinedField>

......将是:

<UserDefinedFields>
  <UserDefinedField>
    <Name>ABC</Name>
    <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
    <Name>XYZ</Name>
    <Value>NEWVALUE!</Value>
  </UserDefinedField>
</UserDefinedFields>

实现这一目标的适当XSLT转换是什么?

XSLT 2.0或1.0答案很好......但是首选2.0。

3 个答案:

答案 0 :(得分:1)

您可以使用分组执行此操作:

<xsl:for-each-group 
  select="$doc1//UserDefinedField, $doc2//UserDefinedField" 
  group-by="Name">
  <xsl:copy-of select="current-group()[last()]"/>
</xsl:for-each-group>

答案 1 :(得分:0)

假设您指示处理器处理“初始”XML文档,并提供“覆盖”文档的路径作为参数,您可以这样做:

XSLT 2.0

<xsl:stylesheet version="2.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="path-to-update">update.xml</xsl:param>
<xsl:key name="fld" match="UserDefinedField" use="Name" />

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

<xsl:template match="Value">
    <xsl:variable name="update" select="key('fld', ../Name, document($path-to-update))" />
    <xsl:copy>
        <xsl:value-of select="if ($update) then $update/Value else ."/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

答案 2 :(得分:0)

只需使用此模板覆盖身份规则

  <xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()">
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/>
  </xsl:template>

这里我假设第二个文档有一个文档元素(顶部元素),并且可以包含不同深度的许多UserDefinedField个元素。仅为方便起见,第二个文档在转换中内联 - 在实际情况下,可以使用doc()函数。我还声明<xsl:key>使用第二个文档中Name孩子的UserDefinedField值来有效地找到新值。

以下是完整转型

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

 <xsl:key name="kFieldByName" match="Value" use="../Name"/>

 <xsl:variable name="vDoc2">
  <patterns>
    <UserDefinedField>
      <Name>XYZ</Name>
        <Value>NEWVALUE!</Value>
      </UserDefinedField>
    </patterns>
 </xsl:variable>

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

  <xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()">
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/>
  </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<UserDefinedFields>
  <UserDefinedField>
    <Name>ABC</Name>
    <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
    <Name>XYZ</Name>
    <Value>645q3245</Value>
  </UserDefinedField>
</UserDefinedFields>

产生了想要的正确结果

<UserDefinedFields>
  <UserDefinedField>
      <Name>ABC</Name>
      <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
      <Name>XYZ</Name>
      <Value>NEWVALUE!</Value>
  </UserDefinedField>
</UserDefinedFields>