xml - XSL - 替换其他结构中同名的节点值

标签 xml xslt

我正在尝试替换一些节点值。思路是在其他结构中查找同名节点并替换该值。

在这里,我使用 Rule/A 更改 Body/A 和使用 Rule/D 更改 Body/C/D 的值。

类似这样的事情。

<Message>
<XMLNSC>
    <MaXML>
        <Rule>
            <A>RuleA</A>
            <D>RuleD</D>
            <E>RuleE</E>
        </Rule>
        <Body>
            <A>valA</A>
            <B>valB</B>
            <C>
                <D>valD</D>
            </C>
        </Body>
    </MaXML>
</XMLNSC>

对此。

<Message>
<XMLNSC>
    <MaXML>
        <Rule>
            <A>RuleA</A>
            <D>RuleD</D>
            <E>RuleE</E>
        </Rule>
        <Body>
            <A>RuleA</A>
            <B>valB</B>
            <C>
                <D>RuleD</D>
            </C>
        </Body>
    </MaXML>
</XMLNSC>

当前我正在循环所有子节点,搜索节点名称之间的匹配,但是我应该如何保持相同的结构并仅更改值?

<?xml version="1.0" encoding="utf-8"?>

<xsl:output method="xml" indent="yes"/>

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

<!-- match Body -->
<xsl:template match="Body">
    <Body>
        <!-- all children from body -->
        <xsl:for-each select="descendant::*">
            <xsl:variable name="maNode" select="."/>
            <xsl:variable name="nodeName" select="name()"/>
            <!-- all rules -->
            <xsl:for-each select="//Rule/*">
                <xsl:variable name="varRuleName" select="name()"/>  
                <xsl:choose>
                    <!-- match rule -->
                    <xsl:when test="$nodeName = $varRuleName">
                        <element name="match"/>
                        <xsl:copy>
                            <xsl:apply-templates select="@* | node()"/>
                        </xsl:copy>
                    </xsl:when>
                    <xsl:otherwise>
                        <element name="unmatch"/>
                        <xsl:copy>
                            <xsl:apply-templates select="@* | node()"/>
                        </xsl:copy>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:for-each>
    </Body>
</xsl:template>

最佳答案

使用身份模板的方法

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

很好,现在要使用它,您只需为要更改的元素添加模板即可,例如

  <xsl:template match="Body/A">
      <xsl:copy>
          <xsl:value-of select="ancestor::MaXML/Rule/A"/>
      </xsl:copy>
  </xsl:template>

https://xsltfiddle.liberty-development.net/pPqsHTK

应该很清楚我希望如何添加第三个匹配Body/C/D的模板,并根据需要从相应的Rule中选择值。

如果您需要通用方法,那么在 XSLT 2 或 3 中,可以通过子树中的键和键函数调用轻松实现:

  <xsl:key name="ref" match="MaXML/Rule/*" use="node-name()"/>

  <xsl:template match="Body//*[key('ref', node-name(), ancestor::MaXML)]">
      <xsl:copy>
          <xsl:value-of select="key('ref', node-name(), ancestor::MaXML)"/>
      </xsl:copy>
  </xsl:template>

完整的 XSLT 3 位于 https://xsltfiddle.liberty-development.net/pPqsHTK/3那么就是

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:key name="ref" match="MaXML/Rule/*" use="node-name()"/>

  <xsl:template match="Body//*[key('ref', node-name(), ancestor::MaXML)]">
      <xsl:copy>
          <xsl:value-of select="key('ref', node-name(), ancestor::MaXML)"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

不幸的是,XSLT 1 没有 key 函数的第三个参数,因此要使用键实现通用方法,您需要包含 generate-id(ancestor::MaXML) 在键值中:

  <xsl:key name="ref" match="MaXML/Rule/*" use="concat(generate-id(ancestor::MaXML), '|', name())"/>

  <xsl:template match="Body//*[key('ref', concat(generate-id(ancestor::MaXML), '|', name()))]">
      <xsl:copy>
          <xsl:value-of select="key('ref', concat(generate-id(ancestor::MaXML), '|', name()))"/>
      </xsl:copy>
  </xsl:template>

示例位于 https://xsltfiddle.liberty-development.net/pPqsHTK/4 .

关于xml - XSL - 替换其他结构中同名的节点值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52008878/

相关文章:

xml - 用Jackson和Kotlin反序列化xml namespace

c++ - 检索标签之间的值 XML Xerces C++ Parser

objective-c - 为什么 NSXMLDocument 不转义换行符 (\n)

python - 通过使用 Python 修改 Excel 后面的 xml 来动态更改 Excel 中的文件共享根目录

xml - 从 for-each 中的值更改 XPath 查询

java - Android:需要格式化布局的帮助

xml - 按 XSL 中的 2 个字段分组

linux - 如何将应用模板的值存储在变量中?

xslt - 如何在 XSLT 中使用内联条件(if then else)?

xml - 如何通过 xslt 在 xml 文件中按名称计算节点?