簡體   English   中英

如何使用XSL刪除XML節點的第一個子節點?

[英]How to remove the first child of an XML node with XSL?

Data.xls

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="Data" select="document('Data.xml')/*[1]"/>

<xsl:template match="/">
  <xsl:call-template name="remove-first-child">
    <xsl:with-param name="Node" select="$Data"/>
  </xsl:call-template>
</xsl:template>

<xsl:template name="remove-first-child">
  <xsl:param name="Node"/>
  <xsl:element name="{name($Node)}">
    <xsl:copy-of select="$Node/@* | $Node/*[position() > 1]"/>
  </xsl:element>
</xsl:template>

<!-- same as above, but for testing over 2 recursion levels -->
<xsl:template name="remove-first-child1">
  <xsl:param name="Node"/>
  <xsl:call-template name="remove-first-child">
    <xsl:with-param name="Node">
      <xsl:element name="{name($Node)}">
        <xsl:copy-of select="$Node/@* | $Node/*[position() > 1]"/>
      </xsl:element>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

</xsl:stylesheet>

如何刪除數據中的第一個孩子並產生可以再次傳遞給remove-first-child的輸出?

調用第一個模板時,我得到:

$> msxsl Other.xml Data.xsl
<Alphabet>
  <B/>
  <C/>
  ...
</Alphabet>

當我更改為調用第二個模板時,我得到:

$> msxsl Other.xml Data.xsl
Error occured while executing stylesheet 'Data.xsl'.
Code:  0x80004005
Reference to variable or parameter 'Node' must evaluate to a node list.

理想的結果將是:

<Alphabet>
  <C/>
  ...
</Alphabet>

更新:我如何嘗試應用建議的解決方案。

<xsl:template match="node()|@*" mode="remove-first-child">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*" mode="remove-first-child"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()[parent::*][not(preceding-sibling::*)]" mode="remove-first-child"/>

<xsl:template name="remove-first-child-a">
  <xsl:param name="Node"/>
  <xsl:apply-templates select="$Node" mode="remove-first-child"/>
</xsl:template>

<xsl:template name="remove-first-child-b">
  <xsl:param name="Node"/>
  <xsl:variable name="Temp">
    <xsl:apply-templates select="$Node" mode="remove-first-child"/>
  </xsl:variable>
  <xsl:apply-templates select="$Temp" mode="remove-first-child"/>  
</xsl:template>

<xsl:template match="/">
  <xsl:call-template name="remove-first-child-a">
  <!-- xsl:call-template name="remove-first-child-b" -->
    <xsl:with-param name="Node" select="$Data"/>
  </xsl:call-template>
</xsl:template>

但這也只會產生與上述相同的結果。 a

$> msxsl Other.xml Data.xsl
<Alphabet>
  <B/>
  <C/>
  ...
</Alphabet>

b

$> msxsl Other.xml Data.xsl
Error occured while executing stylesheet 'Data.xsl'.
Code:  0x80004005
Expression must evaluate to a node-set.
-->$Temp<--

所以我想關鍵是類型系統...

並且要注意:主要操作發生在Other.xml ,這不僅僅是一個虛擬調用。 一些數據是從Data.xml的,在與Other.xsl之前將要進行處理。 該處理僅包括刪除依賴於某些條件(不是此問題的一部分)的第一個子對象,這些條件恰好是遞歸實現的,因為它是XSL。 並且在遞歸過程中,可能有必要刪除相同和不同的遍歷節點的多個第一個子級。

我想在XSL中表示的是投影node --> node ,刪除輸入節點的第一個子節點。

對於XSLT中的這種遞歸(即,遵循輸入文檔的結構),您要使用apply-templates而不是call-template 這避免了您遇到的問題(缺少節點集),因為該模板將僅應用於存在的節點。

以下轉換設置了一個標准的身份模板,然后添加了對第一個子對象不產生任何影響的替代。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- Standard identity template -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

    <!-- Skip first child -->
    <!-- the "parent" check is needed so that the root node is not skipped -->
    <xsl:template match="node()[parent::*][not(preceding-sibling::*)]" />

    <xsl:variable name="data-doc" select="document('Data.xml')"/>

    <xsl:template match="/">
        <xsl:apply-templates select="$data-doc/*" />
    </xsl:template>

</xsl:stylesheet>

應用於虛擬文檔,其中外部文件Data.xml包含以下示例輸入,

<A>
    <B1>
        <C1 />
        <C2 />
    </B1>
    <B2>
        <C1 />
        <C2 />
    </B2>
    <B3>
        <C1 />
        <C2>
            <D1 />
            <D2 />
        </C2>
        <C3>
            <D1 />
        </C3>
    </B3>
</A>

結果如下:

<?xml version="1.0" encoding="utf-8"?>
<A>
    <B2>
        <C2 />
    </B2>
    <B3>
        <C2>
            <D2 />
        </C2>
        <C3>
        </C3>
    </B3>
</A>

您可以使用 :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/*//*[position()&lt;=1]"/>     
</xsl:stylesheet>

如果要同時過濾第一個和第二個元素,則將“ 1”乘“ 2”(按harpo的答案中的說明工作)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM