簡體   English   中英

XSLT - 匹配具有相同標記名稱的元素

[英]XSLT - Match Elements with same Tag Name

作為輸入xml示例我有

<Elem1>
    <Obj name="1">
    <Obj name="2">
    <Obj name="3">
</Elem1>

使用xslt規則我想獲得類似下面的內容

<Elem1>
    <Obj1 name="1">
    <Obj2 name="2">
    <Obj3 name="3">
</Elem1>

基本上,如果子元素的名稱相同,我想在名稱后附加第一個屬性的名稱。

我找到了很多可以匹配的示例,但只有當您知道元素的名稱時才會這樣。 有沒有辦法在不事先知道元素名稱的情況下匹配這種情況例如:

<Elem1>
    <Second name="1">
    <Second name="2">
    <Second name="3">
</Elem1> 

也會回來

    <Elem1>
        <Second1 name="1">
        <Second2 name="2">
        <Second3 name="3">
    </Elem1> 

在此先感謝您的幫助。

嘗試這個

<xsl:template match="*[@name][count(../*[name() = current()/name()]) > 1]">
    <xsl:element name="{name()}{@name}">
        <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
</xsl:template>

對於復制其他數據,使用身份轉換為

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

使用XSLT 2或3中的密鑰精煉Rupesh的精細答案

  <xsl:key name="group-by-name" match="*[@name]" use="node-name(.)"/>

  <xsl:template match="*[@name and key('group-by-name', node-name(.), ..)[2]]">
      <xsl:element name="{name()}{@name}" namespace="{namespace-uri()}">
          <xsl:apply-templates select="@* | node()"/>
      </xsl:element>
  </xsl:template>

https://xsltfiddle.liberty-development.net/eiZQaF4/1

雖然考慮它的時間稍長,如果有一個元素具有子孫,或者與key函數的第三個參數同名的后代只允許將搜索限制為子樹而不是接受的答案,它可以給出不同的結果。到某個級別的子樹。

Rupesh_Kr答案非常通用,適用於任何情況。

但是,如果要使用特定的xpath ,您只想根據規則更改節點,則可以使用以下stylesheet

INPUT:

<?xml version="1.0"?>
<Elems>
  <Elem>
    <Obj1 name="1"/>
    <Obj2 name="2"/>
    <Obj3 name="3"/>
  </Elem>
  <Elem>
    <Second name="1"/>
    <Second name="2"/>
    <Second name="3"/>
  </Elem>
</Elems>

樣式表:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:redirect="http://xml.apache.org/xalan/redirect" xmlns:xalan="http://xml.apache.org/xslt" version="1.0" extension-element-prefixes="redirect">
  <xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/Elems/Elem"> <!-- only for those nodes you do a specific process -->
    <!-- variable to store the name of the first child -->
    <xsl:variable name="subNodeName" select="local-name(./*[1])"/>
    <!-- variable to store the number of children -->
    <xsl:variable name="countNodes" select="count(./*)"/>
    <xsl:choose>
      <xsl:when test="$countNodes=count(./*[local-name()=$subNodeName])"><!--when all children have the same name -->
        <Elem>
          <xsl:for-each select="./*">
            <xsl:element name="{name()}{@name}">
              <xsl:apply-templates select="node() | @*"/>
            </xsl:element>
          </xsl:for-each>
        </Elem>
      </xsl:when>
      <xsl:otherwise>
        <Elem>
          <xsl:apply-templates select="node() | @*"/>
        </Elem>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

OUTPUT:

<?xml version="1.0"?>
<Elems>
  <Elem>
    <Obj1 name="1"/>
    <Obj2 name="2"/>
    <Obj3 name="3"/>
  </Elem>
  <Elem>
    <Second1 name="1"/>
    <Second2 name="2"/>
    <Second3 name="3"/>
  </Elem>
</Elems>
 <xsl:template match="Elem1">
        <xsl:element name="Elem1">
            <xsl:for-each select="Obj">
                <xsl:element name="{concat(local-name(),position())}">
                    <xsl:apply-templates select="@*"/>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

你也可以使用這個xslt

暫無
暫無

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

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