[英]XSLT 1.0 - Merge sibling nodes with child nodes into new composite nodes
[英]XSLT 1.0 insert multiple new nodes in sequence
我需要通過將新元素及其子元素添加到較舊版本來將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中所需的元素的名稱以'R'開頭,類似地,v1中可選和不存在的元素的名稱以'O'和'A'開頭。 v1中必需和可選元素的名稱以'R'和'O'結尾。 因此,我們有六個案例,在這里用AO,AR,OO,OR,RO,RR元素表示。 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:choose進行遵循,請使用它代替上面顯示的代碼。 如果您發現應用模板,然后找到if模板,那么請使用它。
<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內容模型都是平面序列的主要原因。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.