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

XSLT使用基于子节点值的匹配替换元素,xslt,xslt-2.0,Xslt,Xslt 2.0,我有以下源XML文档: <UserDefinedFields> <UserDefinedField> <Name>ABC</Name> <Value>123</Value> </UserDefinedField> <UserDefinedField> <Name>XYZ</Name> <Value>645q3245<

我有以下源XML文档:

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

基础知识
123
XYZ
645q3245
如果存在匹配的
值,我希望覆盖输入XML中的匹配节点。。换句话说,合并的最终结果是:

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

XYZ
新价值!
。。。将是:

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

基础知识
123
XYZ
新价值!
实现这一点的适当XSLT转换是什么


XSLT 2.0或1.0答案很好。。。2.0首选。

您可以通过分组来实现这一点:

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

假设您指示处理器处理“初始”XML文档,并将“覆盖”文档的路径作为参数提供,则可以执行以下操作:

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

update.xml

只需使用此模板覆盖标识规则即可

  <xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()">
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/>
  </xsl:template>
<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>
<UserDefinedFields>
  <UserDefinedField>
      <Name>ABC</Name>
      <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
      <Name>XYZ</Name>
      <Value>NEWVALUE!</Value>
  </UserDefinedField>
</UserDefinedFields>
在提供的XML文档上应用此转换时:

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

基础知识
123
XYZ
645q3245
生成所需的正确结果

  <xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()">
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/>
  </xsl:template>
<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>
<UserDefinedFields>
  <UserDefinedField>
      <Name>ABC</Name>
      <Value>123</Value>
  </UserDefinedField>
  <UserDefinedField>
      <Name>XYZ</Name>
      <Value>NEWVALUE!</Value>
  </UserDefinedField>
</UserDefinedFields>

基础知识
123
XYZ
新价值!

Kay博士,我的理解是否正确,提议的解决方案将输出与任何
$doc1//UserDefinedField
元素都不匹配的
$doc2//UserDefinedField
元素?如果是这样,这不是OP想要的——他只想输出这样的
$doc2//UserDefinedField
元素,这些元素与
$doc1
中的元素相匹配(“覆盖”)我不确定OP的需求从何而来,但是是的,我的解决方案假设如果doc2中有一个条目与doc1中的条目不匹配,doc2中的条目将添加到输出中。如果这不是你想要的,你可以用
If(current-group()[1]/(/)是$doc1)这样的东西来调整解决方案,然后…
Kay博士,Re:“flag我不确定你对OP要求的解读来自何方”。这不仅仅是我的阅读——这完全符合问题中的规定:“如果存在匹配值,我想从输入XML中覆盖匹配节点…”注意if…@DimitreNovatchev要求中没有任何内容说明第二个文件中与第一个文件中的任何内容不匹配的值应该如何处理。三种可行的策略是(a)将它们添加到输出中,(b)忽略它们,(c)报告错误。你选择(b),我选择(a)。Kay,一般来说,当没有指定任何内容时,我选择什么也不做