我想通过将新内容合并到现有文件来更新XML文件。除了要合并的内容(文件B)之外,现有文件(A)中的所有内容都应保持不变,在本例中为“描述”节点。
我的问题类似于this one。但是,我在答案中遇到的限制是不一定保留节点顺序。如果可能的话,我希望保留原始节点顺序。我当前的XSL只执行以下操作:
我的XSL和XML如下。请注意,我仅限于XSLT 1.0
<xsl:variable name="desc" select="document('doc.out.xml')" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="//*[name=$desc//node/@name]">
<xsl:variable name="name" select="current()/name" />
<xsl:copy>
<xsl:apply-templates select="$desc//node[@name=$name]/description" />
<xsl:apply-templates select="@*|node()[not(self::description)]" />
</xsl:copy>
</xsl:template>
<renderer>
<name>key</name>
<description>
The key element is an Object Element used to create and
identify rows.
</description>
<foo>blah</foo>
<fields>
<field>
<name>elements</name>
<description>
A container for all 'element' nodes.
</description>
<bar>blah</bar>
<factory>
<localRenderer>
<name>element</name>
<description>
A primitive object and arrays thereof.
</description>
<baz>blah</baz>
<fields>
<field>
<name>name</name>
<description>
Alias by which the element may be referenced.
</description>
<bar>blah</bar>
</field>
<field>
<name>type</name>
<description>
Type of the data.
</description>
<bar>blah</bar>
</field>
</fields>
</localRenderer>
</factory>
</field>
</fields>
</renderer>
<root>
<node name="key">
<description>The key element is an Object Element used to create and
identify rows.Note that object declaration via XML must occur within
a definitions element. See for more information.</description>
<subnodes>
<node name="elements">
<description>
Hi. This is a test.
</description>
<subnodes>
<node name="element">
<description>A primitive object and arrays thereof. TEST</description>
<subnodes>
<node name="name">
<description>Alias by which the element may be referenced.
</description>
</node>
<node name="type">
<description>Type of the data; a primitive object of array
thereof. </description>
</node>
</subnodes>
</node>
</subnodes>
</node>
</subnodes>
</node>
</root>
请注意,描述现在是第一个节点。
<renderer>
<description>The key element is an Object Element used to create and
identify rows.Note that object declaration via XML must occur within
a definitions element. See for more information.
</description>
<name>key</name>
<foo>blah</foo>
<fields>
<field>
<description>
Hi. This is a test.
</description>
<name>elements</name>
<bar>blah</bar>
<factory>
<localRenderer>
<description>A primitive object and arrays thereof. TEST
</description>
<name>element</name>
<baz>blah</baz>
<fields>
<field>
<description>Alias by which the element may be referenced.
</description>
<name>name</name>
<bar>blah</bar>
</field>
<field>
<description>Type of the data; a primitive object of array
thereof.
</description>
<name>type</name>
<bar>blah</bar>
</field>
</fields>
</localRenderer>
</factory>
</field>
</fields>
</renderer>
答案 0 :(得分:1)
如果您只想更改文档A中的description
节点,那么为了保留顺序,您的XSLT中应该有一个与description
节点匹配的模板,而不是其父节点: / p>
<xsl:template match="description">
然后通过查看前面的兄弟
来获取name
<xsl:variable name="name" select="preceding-sibling::name[1]" />
然后,要检查文档B中是否存在节点,您可以使用另一个变量
<xsl:variable name="lookup" select="$desc//node[@name = $name]" />
然后,使用xsl:choose
确定是否从A或B复制描述是一个简单的例子
<xsl:choose>
<xsl:when test="$lookup">
<xsl:copy-of select="$lookup/description" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="identity" />
</xsl:otherwise>
</xsl:choose>
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="desc" select="document('doc.out.xml')" />
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="description">
<xsl:variable name="name" select="preceding-sibling::name[1]" />
<xsl:variable name="lookup" select="$desc//node[@name = $name]" />
<xsl:choose>
<xsl:when test="$lookup">
<xsl:copy-of select="$lookup/description" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="identity" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
请注意,在此处使用xsl:choose
而不是在模板匹配条件中的原因是因为在XSLT 1.0中(根据W3C XSLT specification)它是一个match属性的值包含VariableReference的错误。
这意味着您的XSLT中的模板匹配<xsl:template match="//*[name=$desc//node/@name]">
严格来说是一个错误(尽管某些XSLT 1.0处理器可能不遵循规范并允许它,如您的情况)