我需要通过将新元素及其子女添加到较旧版本来使其与较新版本兼容,从而将XML文件从一个版本转换为另一个版本。(版本1->版本2)其中版本2具有一些新的必需元素。如果缺少元素或缺失的孩子,我们需要添加默认值。序列在这里也很重要。
例如版本1:
<root>
<a>
<a1>A1</a1>
<a2>A2</a2>
</a>
<b>
<b1>B1</b1>
</b>
</root>
版本2:
<root>
<a>
<a1>A1</a1>
<a3>A3</a3>
<a2>A2</a2>
</a>
<c>
<c1>C1</c1>
<c2>C2</c2>
</c>
<d>
<d1>D1</d1>
<d2>D2</d2>
<d3>D3</d3>
</d>
<b>
<b1>B1</b1>
</b>
</root>
我尝试了几件事,但似乎遇到了我无法通过的路障。我为默认值创建变量,以期通过它们循环并根据需要添加。
<xsl:variable name="defaultA">
<a1>aOne<a1>
<a2>aTwo<a2>
</xsl:variable>
.
.
.
<xsl:variable name="defaultC">
<c1>cOne<c1>
<c2>cTwo<c2>
</xsl:variable>
<xsl:variable name="defaultB">
<b1>bOne<b1>
<b2>bTwo<b2>
</xsl:variable>
<xsl:template match="root">
<xsl:variable name="defaults" select="document('')/*/xsl:variable[contains(@name,'default')]/*" />
<xsl:variable name="defaultNodes" select="ext:node-set($defaults)"/>
<xsl:copy>
<xsl:for-each select="$defaultNodes">
<xsl:copy-of select="node()[not(name() = name(current()))]"/>
</xsl:for-each>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
这将添加节点,但它将命名空间添加到元素(我不需要),如果它们已经存在,则将继续添加元素事件。
任何帮助将我朝正确方向移动的帮助将不胜感激。预先感谢。
最方便的方法在很大程度上取决于您的内容模型的外观,以及是否存在V2中所需的任何元素,但在V1中是可选的。
从你说的话,我想
- V1中允许的每个元素在V2中仍然合法,应保留。
- V2中需要一些V1中的一些元素;如果它们在实例中存在,则应保留它们,如果缺乏,则应提供默认值。
- 内容模型是元素的平坦序列,没有重复,也没有子组。
- v1中元素的序列是V2中的元素(即有效V1实例中的所有元素都保留其在V2中的相对位置)。
如果这些猜测是错误的,则需要在答案中进行适当的调整(您可能会考虑尝试更清楚您的问题)。
然后有几种情况要考虑:
- v2中需要元素,可选或不存在V1中的元素。
- 元素在V2中是可选的,并且需要,可选或在V1中不存在。
作为一个例子,让我们假设V1中所需的一个元素具有一个名称以" R"开头,并且类似的元素可选,而V1中的元素则具有开始名称为" O"one_answers" A"。V1中所需的元素和可选的元素结束了" R"one_answers" O"的名称。因此,我们有六个案例,在此处由AO,AR,OO或RO,RR的Elements代表。V1的内容模型是(OO?, OR?, RO, RR)
,V2的内容模型为(AO?, AR, OO?, OR, RO?, RR)
。
一个简单的模板来处理父元素(我称其为p)看起来像这样(未测试):
<xsl:template match="P">
<!--* AO is optional and will never appear in v1 input.
* So we do nothing. *-->
<!--* AR is required and will never appear in v1 input.
* So we inject it unconditionally. *-->
<xsl:call-template name="default-AR"/>
<!--* OO is optional and might appear in v1 input.
* So we keep it if it's here. *-->
<xsl:apply-templates select="OO"/>
<!--* OR is required and might appear in v1 input.
* We keep it if it's already present and supply a
* default version if it's missing. *-->
<xsl:apply-templates select="OR"/>
<xsl:if test="not(OR)">
<xsl:call-template name="default-OR"/>
</xsl:if>
<!--* RO is optional but will always appear in v1 input.
* We keep it. *-->
<xsl:apply-templates select="RO"/>
<!--* RR is required in v1 and v2. Just keep it. *-->
<xsl:apply-templates select="RR"/>
</xsl:template>
如果从现在开始六个月后阅读此样式表格时,您会找到元素的逻辑,或更易于使用XSL:选择,使用它代替上面显示的代码。如果您找到申请图,然后找到易于遵循的效果,请使用它。
<xsl:choose>
<xsl:when test="OR">
<xsl:apply-templates select="OR"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="default-OR"/>
</xsl:otherwise>
</xsl:choose>
如果内容模型不是平坦的序列,则模板的逻辑可能会变得更加复杂。在一般情况下,尚不清楚从V1转换为具有更多元素类型的V2的翻译,并且内容模型中可能有不同的结构。(您认为这是我猜测V1和V2内容模型都是平面序列的主要原因。)