給定一個深度嵌套的XML樹,我想找到某個元素。在那一點上,我想將X包裝在一個與更高元素處於同一級別的新元素中。然後我想從「某些」元素之後的點開始繼續使用原始樹的其餘部分。如何使用XSLT拆分嵌套結構?
例如,假設該輸入:
<root>
<branch att="yo">
<div stuff="no">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</branch>
</root>
我想找到項目2在< UL>(易peasy)。我想在項目2之前插入一個新的分支級元素。然後我想繼續使用項目2(繼續祖先節點)。也就是說,我想這樣的輸出:
<root>
<branch att="yo">
<div stuff="no">
<ul>
<li>Item 1</li>
</ul>
</div>
</branch>
<branch>
<div>
<p>New branch here</p>
</div>
</branch>
<branch att="yo">
<div stuff="no">
<ul>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</branch>
</root>
我有一個很難的問題開始使用此,爲了使廣義解。我認爲它會涉及多種模式或鍵以及處理祖先節點以查找節點名稱和屬性。任何幫助表示讚賞。
好吧,這是我迄今爲止。它部分地工作(例如,我複製了一些節點但沒有屬性;我複製了太多的節點,但這是我認爲的一個開始)。我的想法是,我需要一個遞歸函數。我從我關心的最遠祖先(分支)開始,對於每個最終後代是特定元素(li「item 2」)的每個子節點,我複製每個節點及其屬性,將其附加到前一個節點(即什麼newNewTree是)。並且我遞歸直到到達某個元素(li的第2項),此時我返回NewNewTree變量,我的意圖是將它作爲正確祖先元素的樹(沒有文本)。爲了使這項工作,我認爲我需要做的是通過一個身份模板覆蓋從該函數處理每個節點,複製該節點及其屬性。但是今天晚上太累了,無法嘗試。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://www.example.com"
exclude-result-prefixes="xs my"
version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:sequence select="$origNodesNoText" />
</xsl:template>
<xsl:variable name="ancestorElemName" select="'div'" />
<xsl:variable name="origNodesNoText">
<xsl:apply-templates select="/" mode="origNodesNoText"/>
</xsl:variable>
<xsl:template match="text()" mode="origNodesNoText"/>
<xsl:template match="li[.='Item 2']" mode="origNodesNoText">
<xsl:variable name="newTree">
<xsl:element name="{local-name(ancestor::*[local-name()=$ancestorElemName][1])}">
<xsl:for-each select="ancestor::*[local-name()=$ancestorElemName][1]/attribute::*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<xsl:sequence select="my:split(ancestor::*[local-name()=$ancestorElemName][1],.,$newTree)" />
</xsl:template>
<xsl:function name="my:split">
<xsl:param name="ancestorElemNode" />
<xsl:param name="callingNode" />
<xsl:param name="newTree" />
<xsl:message>Calling my split</xsl:message>
<xsl:choose>
<xsl:when test="$ancestorElemNode ne $callingNode">
<xsl:message>Found a node to copy its name and attributes</xsl:message>
<xsl:variable name="newNewTree">
<xsl:for-each select="$newTree/node()">
<xsl:copy /> <!-- doesn't copy attribute nodes so not what we want -->
</xsl:for-each>
<xsl:element name="{local-name($ancestorElemNode)}">
<xsl:for-each select="$ancestorElemNode/attribute::*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<xsl:sequence select="my:split($ancestorElemNode/child::*[descendant::*[. eq $callingNode]][1],$callingNode,$newNewTree)" />
</xsl:when>
<xsl:otherwise>
<xsl:message>Found the end point</xsl:message>
<xsl:sequence select="$newTree" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
W¯¯流。謝謝。那個好漂亮。只有一個問題,分支上的@att不會在香蕉後複製。我做了一個改變,它使它起作用,我不確定這個改變的其他後果是什麼。 (我不熟悉<<構造)。以下是我必須做的: – user5923
在此模板中: 在選擇,我已經當到本作空:的 –
user5923
我還沒有發現負面效應的變化了xsl:when元素我提到。先生非常感謝您。 – user5923