【问题标题】:xml xslt transformxml xslt 转换
【发布时间】:2011-09-26 15:28:06
【问题描述】:

我一直在尝试使用 XSLT 将一些简单的 XML 转换为另一种简单的 XML。我是 XSLT 的新手,所以如果有人能给我一个例子,我会扩展它。

我有任意 XML 文件:例如

<element>
 <child_element>
  <grandchild_element>
     only one
  </grandchild_element>
 </child_element>
 <child_element>
  <grandchild_element>
     one
  </grandchild_element>
  <grandchild_element>
     two
  </grandchild_element>
 </child_element>
</element>

我想从中生产:

<tree>
 <item class="element" id="1">
  <item class="child_element" id="11">
   <item class="grandchild_element" id="111" value="only one"/>
  </item>
  <item class="child_element" id="12">
   <item class="grandchild_element" id="121" value="only one"/>
   <item class="grandchild_element" id="122" value="only one"/>
  </item>
 </item>
</tree>

谢谢!

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    最简单/最短的解决方案之一(只有 3 个模板,没有模式,没有轴,没有 count(),只有一个 xsl:attribute),同时也是最通用的(适用于任何元素名称)

    <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="/">
      <tree>
       <xsl:apply-templates/>
      </tree>
     </xsl:template>
    
     <xsl:template match="*">
      <xsl:variable name="vNumber">
       <xsl:number count="*" level="multiple"/>
      </xsl:variable>
    
      <item class="{name()}"
            id="{translate($vNumber, '.', '')}">
       <xsl:apply-templates/>
      </item>
     </xsl:template>
    
     <xsl:template match="text()">
      <xsl:attribute name="value">
       <xsl:value-of select="normalize-space()"/>
      </xsl:attribute>
     </xsl:template>
    </xsl:stylesheet>
    

    当此转换应用于提供的 XML 文档时

    <element>
     <child_element>
      <grandchild_element>
         only one
      </grandchild_element>
     </child_element>
     <child_element>
      <grandchild_element>
         one
      </grandchild_element>
      <grandchild_element>
         two
      </grandchild_element>
     </child_element>
    </element>
    

    产生想要的正确结果

    <tree>
       <item class="element" id="1">
          <item class="child_element" id="11">
             <item class="grandchild_element" id="111" value="only one"/>
          </item>
          <item class="child_element" id="12">
             <item class="grandchild_element" id="121" value="one"/>
             <item class="grandchild_element" id="122" value="two"/>
          </item>
       </item>
    </tree>
    

    【讨论】:

      【解决方案2】:

      您会为每个元素编写一个模板,例如:

      <xsl:template match="child_element">
      

      并使用前面或前面的兄弟元素的计数来获取“id”字段:

      <xsl:template match="child_element">
          <item>
              <xsl:attribute name="id">
                  <xsl:value-of select="concat(count(preceding-sibling::element),count(preceding::child_element)+1)"/>
              </xsl:attribute>
          </item>
      </xsl:template>
      

      对于孙子 ID,您必须使用 .. 和前兄弟姐妹。 但是,我强烈建议您不要使用当前的 id 计数方案:一旦您在任何级别拥有超过 10 个节点,就会发生冲突。

      【讨论】:

        【解决方案3】:

        要获取每个元素的 id,您需要回顾每个祖先,并为每个级别计算前兄弟的数量。

        <xsl:attribute name="id">
            <xsl:apply-templates select="ancestor-or-self::*" mode="id"/>
        </xsl:attribute>
        
        <xsl:template match="*" mode="id">
           <xsl:value-of select="count(preceding-sibling::*) + 1"/>
        </xsl:template>
        

        将元素名称转换为 class 属性很简单,如下所示:

        <xsl:attribute name="class">
           <xsl:value-of select="local-name()"/>
        </xsl:attribute>
        

        而将文本转换成value属性也相当简单。

        <xsl:template match="text()">
           <xsl:attribute name="value">
              <xsl:value-of select="normalize-space(.)"/>
           </xsl:attribute>
        </xsl:template>
        

        此处的 normalize-space 用于删除示例 XML 中显示的换行符。

        这是完整的 XSLT

        <?xml version="1.0"?>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        
           <!-- Match root element -->
           <xsl:template match="/">
              <tree>
                 <xsl:apply-templates select="node()"/>
              </tree>
           </xsl:template>
        
           <!-- Match any element in the XML -->
           <xsl:template match="*">
              <item>
                 <xsl:attribute name="id">
                    <xsl:apply-templates select="ancestor-or-self::*" mode="id"/>
                 </xsl:attribute>
                 <xsl:attribute name="class">
                    <xsl:value-of select="local-name()"/>
                 </xsl:attribute>
                 <xsl:apply-templates select="@*|node()"/>
              </item>
           </xsl:template>
        
           <!-- Used to match ancestors to work out the id -->
           <xsl:template match="*" mode="id">
              <xsl:value-of select="count(preceding-sibling::*) + 1"/>
           </xsl:template>
        
           <!-- Convert text into the value attribute -->
           <xsl:template match="text()">
              <xsl:attribute name="value">
                 <xsl:value-of select="normalize-space(.)"/>
              </xsl:attribute>
           </xsl:template>
        
           <!-- Copy any existing attributes in the XML -->
           <xsl:template match="@*">
              <xsl:copy/>
           </xsl:template>
        </xsl:stylesheet>
        

        当应用于您的示例 XML 时,将输出以下内容:

        <tree>
           <item id="1" class="element">
              <item id="11" class="child_element">
                 <item id="111" class="grandchild_element" value="only one"/>
              </item>
              <item id="12" class="child_element">
                 <item id="121" class="grandchild_element" value="one"/>
                 <item id="122" class="grandchild_element" value="two"/>
              </item>
           </item>
        </tree>
        

        【讨论】:

          猜你喜欢
          • 2019-10-06
          • 1970-01-01
          • 2020-07-28
          • 1970-01-01
          • 2015-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多