如何通过转换将元素添加到嵌套列表?

时间:2011-05-18 11:50:38

标签: xml list xslt

假设我们在XML中有这样的嵌套列表:

<section name="SomeSection">
    <!-- list property -->
    <property length="2" name="ExternalList">
        <!-- first element of external list -->
        <listItem name="ExtElement1">
            <property length="3" name="InternalList1">
                <listItem name="SomeElement1" />
                <listItem name="SomeElement2" />
                <listItem name="SomeElement3" />
            </property>
        </listItem>
        <!-- second element of external list -->
        <listItem name="ExtElement2">
            <property length="2" name="InternalList1">
                <listItem name="SomeElement1" />
                <listItem name="SomeElement2" />
            </property>
        </listItem>
    </property>
</section>

我们有一些新项目,例如:

<listItem name="SomeElement3" />

什么转换在'ExtElement2'处向'InternalList1'添加'SomeElement3',以及 增加'InternalList1'的'length'属性?

感谢。

2 个答案:

答案 0 :(得分:1)

这个简短的转换使用并覆盖了身份规则

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match=
 "property[@name='ExternalList']
     /listItem[@name='ExtElement2']
       /property[@name='InternalList1']
 ">
  <xsl:copy>
   <xsl:apply-templates select="@*"/>
   <xsl:attribute name="length">
    <xsl:value-of select="@length+1"/>
   </xsl:attribute>
   <xsl:apply-templates/>
   <listItem name="SomeElement3" />
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<section name="SomeSection">
    <!-- list property -->
    <property length="2" name="ExternalList">
        <!-- first element of external list -->
        <listItem name="ExtElement1">
            <property length="3" name="InternalList1">
                <listItem name="SomeElement1" />
                <listItem name="SomeElement2" />
                <listItem name="SomeElement3" />
            </property></listItem>
        <!-- second element of external list -->
        <listItem name="ExtElement2">
            <property length="2" name="InternalList1">
                <listItem name="SomeElement1" />
                <listItem name="SomeElement2" />
            </property></listItem>
    </property>
</section>

产生了想要的正确结果

<section name="SomeSection"><!-- list property -->
   <property length="2" name="ExternalList"><!-- first element of external list -->
      <listItem name="ExtElement1">
         <property length="3" name="InternalList1">
            <listItem name="SomeElement1"/>
            <listItem name="SomeElement2"/>
            <listItem name="SomeElement3"/>
         </property>
      </listItem><!-- second element of external list -->
      <listItem name="ExtElement2">
         <property length="3" name="InternalList1">
            <listItem name="SomeElement1"/>
            <listItem name="SomeElement2"/>
            <listItem name="SomeElement3"/>
         </property>
      </listItem>
   </property>
</section>

请注意:绝对不会在此解决方案的任何位置使用条件XSLT指令 - 它们根本不是必需的。

答案 1 :(得分:0)

这是一个简单的样式表,它将新元素的详细信息作为参数:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:param name="extElement" select="'ExtElement2'" />
  <xsl:param name="intElement" select="'SomeElement3'" />

  <xsl:template match="property[@name='ExternalList']/listItem">
    <xsl:choose>
      <xsl:when test="@name = $extElement">
        <listItem name="{$extElement}">
          <property length="{property/@length+1}" name="{property/@name}">
            <xsl:apply-templates select="property/listItem" />
            <listItem name="{$intElement}" />
          </property>
        </listItem>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="identity" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

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

或者,如果您想将其硬编码到样式表中,您可以执行以下操作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="listItem[@name='ExtElement2']/property">
    <property length="{@length + 1}">
      <xsl:apply-templates select="@*[name() != 'length'] | node()"/>
      <listItem name="SomeElement3" />
    </property>
  </xsl:template>

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

但是你需要在模板的match属性中指定你想要的位置。