如何在XSLT中递归导航

时间:2014-07-23 15:03:10

标签: xml xslt

I am new to XSLT script. I have the input is like as follows:

<?xml version="1.0" encoding="utf-16"?>
<FileDescriptorSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <file>
    <FileDescriptorProto>
      <name>Message</name>
      <dependency />
      <message_type>  

        <DescriptorProto>
          <name>ABCD</name>
          <field>
            <FieldDescriptorProto>
              <name>Type</name>
              <number>10</number>
              <type>TYPE_STRING</type>
            </FieldDescriptorProto>
            <FieldDescriptorProto>
              <name>List</name>
              <number>20</number>
              <type>TYPE_STRING</type>
            </FieldDescriptorProto>
          </field>         
        </DescriptorProto>

        <DescriptorProto>
          <name>XYZ</name>
          <field>
            <FieldDescriptorProto>
              <name>Instance</name>
              <number>1</number>              
              **<type>ABCD</type>**
            </FieldDescriptorProto>
          </field>
        </DescriptorProto>

      </message_type>
    </FileDescriptorProto>
  </file>
</FileDescriptorSet>

在上面的例子中,它有2个DescriptorProto,即ABCD和XYZ。 第二个DescriptorProto XYZ引用了第一个DescriptorProto(ABCD)。 我的问题是当我在XYZ中遇到引用时如何导航到ABCD(在上面的代码中标记为**)。

基本上我想在XYZ中遇到 ABCD 引用时提取ABCD的定义。预期的输出如:

在XYZ下:

--Instance
--1
--Type
--10
--TYPE_STRING
--List
--20
--TYPE_STRING 

1 个答案:

答案 0 :(得分:0)

以下XSLT使用递归调用的模板生成所需的输出。初始调用是通过明确选择名称XYZ给出的类型来完成的。

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

  <!-- explicitly call for the initial type -->
  <xsl:template match="/">
      <xsl:apply-templates select="//DescriptorProto[name='XYZ']" mode="dump"/>
  </xsl:template>

  <!-- recursively handling -->

  <xsl:template match="DescriptorProto" mode="dump">
    <xsl:for-each select="field/FieldDescriptorProto">
      <xsl:text>--</xsl:text><xsl:value-of select="name"/><xsl:text>&#10;</xsl:text>
      <xsl:text>--</xsl:text><xsl:value-of select="number"/><xsl:text>&#10;</xsl:text>
      <xsl:variable name="type_name" select="type"/>
      <xsl:choose>        
        <xsl:when test="//DescriptorProto[name = $type_name]">
          <!-- recurse using the type name -->
          <xsl:apply-templates select="//DescriptorProto[name = $type_name]" mode="dump"/>
        </xsl:when>
        <xsl:otherwise>
          <!-- no further recursion possible (due to base type); just output the type name -->
          <xsl:text>--</xsl:text><xsl:value-of select="$type_name"/><xsl:text>&#10;</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>

  </xsl:template>

</xsl:stylesheet>