xml - XSL - 用不同的值替换相同名称节点的值
问题描述
我正在尝试根据节点 (D) 的值与 Rule/Item 中的值的匹配来替换具有相同名称但结构不同(Body/C 和 Body/E)的节点 (D)。也许像 for-each 之类的东西。
我正在使用两个键,一个带有新值,另一个带有旧值(可能没用),然后我每个一个,但带有新值的那个没有给我任何东西。不应该工作吗?
另一个问题,我想复制匹配节点的父节点,而我的 XSLT 也将“项目”加倍。
输入,
<Message>
<XMLNSC>
<Translator>
<Rule>
<Item>
<D>RuleD1</D>
<New>RuleD1</New> <!-- I guess I don't need an element for this -->
<Original>valD1</Original>
</Item>
<Item>
<D>RuleD2</D>
<New>RuleD2</New> <!-- I guess I don't need an element for this -->
<Original>valD2</Original>
</Item>
</Rule>
<Body>
<A>valA</A>
<B>valB</B>
<C>
<D>valD1</D>
</C>
<E>
<D>valD2</D>
</E>
</Body>
</Translator>
</XMLNSC>
预期的
<Message>
<XMLNSC>
<Translator>
<Rule>
<Item>
<D>RuleD1</D>
<New>RuleD1</New> <!-- I guess I don't need an element for this -->
<Original>valD1</Original>
</Item>
<Item>
<D>RuleD2</D>
<New>RuleD2</New> <!-- I guess I don't need an element for this -->
<Original>valD2</Original>
</Item>
</Rule>
<Body>
<A>valA</A>
<B>valB</B>
<C>
<D>RuleD1</D>
<D_Agg>val1</D_Agg>
</C>
<C>
<D>RuleD1</D>
<D_Agg>val1</D_Agg>
</C>
<E>
<D>RuleD2</D>
<D_Agg>val2</D_Agg>
</E>
<E>
<D>RuleD2</D>
<D_Agg>val2</D_Agg>
</E>
</Body>
</Translator>
</XMLNSC>
这是我的 XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- copy nodes -->
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="ref" match="Translator/Rule//*" use="concat(generate-id(ancestor::Translator), '|', name())"/>
<xsl:key name="ref_new" match="New" use="text()"/>
<xsl:key name="ref_origin" match="Original" use="text()"/>
<!-- duplicate matched node's parent -->
<xsl:template match="Translator//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]]">
<xsl:call-template name="identity"/>
<xsl:call-template name="identity"/>
</xsl:template>
<!-- replace matched node's value -->
<xsl:template match="Body//*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]">
<xsl:variable name="fieldName" select="name()"/>
<xsl:variable name="fieldValue" select="."/>
<!-- <xsl:copy> -->
<!-- <xsl:value-of select="key('ref', concat(generate-id(ancestor::Translator), '|', name()))"/> -->
<!-- </xsl:copy> -->
<xsl:for-each select="key('ref_new', text())">
<xsl:element name="{$fieldName}">
<xsl:value-of select="$fieldValue"/>
</xsl:element>
</xsl:for-each>
<xsl:for-each select="key('ref_origin', text())">
<xsl:element name="{$fieldName}_Agg">
<xsl:value-of select="$fieldValue"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
总而言之作为小提琴:
https ://xsltfiddle.liberty-development.net/pPqsHTM/2
解决方案
因为您的 XSLT 样式表很复杂,而且我不知道什么是重要的,所以我尝试尽可能少地进行更改以达到您想要的结果。
我把你的第二个
xsl:key
改成<xsl:key name="ref_origin" match="Item" use="Original"/>
这使得
D
最后一个使用的孩子可以访问xsl:for-each
,但保留了您的密钥的值。我更改了您的身份调用者模板,以避免在第二次调用前后
Item
添加一个元素xsl:if
<!-- duplicate matched node's parent --> <xsl:template match="Translator//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]]"> <xsl:call-template name="identity" /> <xsl:if test="not(self::Item)"> <xsl:call-template name="identity" /> </xsl:if> </xsl:template>
我在最后添加了另一个元素以
xsl:for-each
添加D
从xsl:key
上述访问的元素<xsl:for-each select="key('ref_origin', text())"> <xsl:element name="{$fieldName}"> <xsl:value-of select="D"/> <!-- Using the D child of the Item from the key --> </xsl:element> <xsl:element name="{$fieldName}_Agg"> <xsl:value-of select="$fieldValue"/> </xsl:element> </xsl:for-each>
现在输出应该符合预期。
推荐阅读
- swiftui - SwiftUI 初始化将存储在 UserDefaults 中的变量
- sql - 如何在没有不符合条件的重复项的情况下进行 JOIN?
- javascript - 如何将对象添加到现有的对象数组
- python - 与熊猫外部合并时出现重复问题
- pyqt - 使用 QTextEdit.clear() 时,PyQt6 无法为位于不同线程中的父级创建子级
- java - Android Studio 如何从 WallpaperManager 获取 Intent 服务
- cplex - 有没有办法在 CPLEX opl 中的 forall 约束语法中用索引表示一个集合?
- angular - MS Teams 等应用程序如何更新
- visual-studio-code - 保存时更漂亮的格式在 CSS 或 HTML 文件中不起作用
- cypress - 如何在 cypress 中循环和读取 JSON 数据