簡體   English   中英

XSLT 1.0依次插入多個新節點

[英]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中允許的每個元素在v2中仍然合法,應該保留。
  • v2中需要一些在v1中可選的元素; 如果它們存在於實例中,則應保留它們,如果不存在,則應提供默認值。
  • 內容模型是元素的平面序列,沒有重復,也沒有子組。
  • v1中元素的順序是v2中元素的順序(也就是說,有效v1實例中的所有元素在v2中都保留了它們的相對位置)。

如果這些猜測是錯誤的,則您需要在答案中進行適當的調整(並且您可能會考慮嘗試使問題更清楚)。

然后有幾種情況需要考慮:

  • 在v2中元素是必需的,在v1中元素是必需的,可選的或不存在的。
  • 元素在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.

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