使用XSLT修改会导致xslt停止工作

时间:2013-05-22 10:28:02

标签: xslt

我有一个XSLT样式表,看起来基本上就像:

<?xml version="1.0" encoding="utf-8" ?>
<!--
** DEV. NOTES:
**  - NOT TESTED YET!
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- *********** Output type definition ************ -->
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:template match="value" mode="values" />

    <!-- ******************************************* VALUE MATCHER ******************************************** -->
    <xsl:template match="value[@name = 'field_name' or @name = 'field_type' or @name = 'field_dim']" mode="values">
        <xsl:variable name="this" select="@name" />
        <!-- Create element for the Name node. -->
        <xsl:if test="$this = 'field_name'">
            <xsl:element name="Name">
                <xsl:value-of select="text()" />
            </xsl:element>
        </xsl:if>
        <!-- *************************************************************** -->
        <!-- Create element for the Type node. -->
        <xsl:if test="$this = 'field_type'">
            <!-- If the type is not a record type. -->
            <xsl:if test="not(text() = 'record')">
                <xsl:element name="Type">
                    <xsl:value-of select="text()" />
                </xsl:element>
            </xsl:if>

            <!-- Else if the Type is record type. -->
            <xsl:if test="text() = 'record'">
                <xsl:element name="Type">RECORD</xsl:element>
            </xsl:if>
        </xsl:if>
        <!-- ********************************************************************* -->
        <!-- Depth & Value for each sub-tree where parenting record is NOT a field -->
        <xsl:if test="$this = 'field_dim' and parent::record[value[@name = 'field_type' and text() != 'record']]">
            <xsl:choose>
                <xsl:when test="text() = '0'">
                    <!-- A simple variable is allowed. -->
                    <xsl:element name="Depth">SIMPLE</xsl:element>
                    <xsl:element name="Value">{NS}</xsl:element>
                </xsl:when>
                <xsl:when test="text() = '1'">
                    <!-- The parameter has the type of Array<T>. -->
                    <xsl:element name="Depth">ARRAY</xsl:element>
                    <xsl:element name="Value">{{NS}}</xsl:element>
                </xsl:when>
                <xsl:when test="text() = '2'">
                    <!-- The parameter is some kind of hash table like: java.util.Map<String, Object> -->
                    <xsl:element name="Depth">MAP</xsl:element>
                    <xsl:element name="Value">
                        <xsl:element name="TKey">{NS}</xsl:element>
                        <xsl:element name="TValue">{NS}</xsl:element>
                    </xsl:element>
                </xsl:when>
                <!-- So far no other stuff is allowed. -->
                <xsl:otherwise />
            </xsl:choose>
        </xsl:if>
        <!-- ***************************************************************** -->
        <!-- Depth & Value for each sub-tree where parenting record is a field -->
        <xsl:if test="$this = 'field_dim' and parent::record[value[@name = 'field_type' and text() = 'record']]">
            <xsl:choose>
                <xsl:when test="text() = '0'">
                    <!-- A simple variable is allowed. -->
                    <xsl:element name="Depth">SIMPLE</xsl:element>
                </xsl:when>
                <xsl:when test="text() = '1'">
                    <!-- The parameter has the type of Array<T>. -->
                    <xsl:element name="Depth">ARRAY</xsl:element>
                </xsl:when>
                <!-- So far no other stuff is allowed. -->
                <xsl:otherwise />
            </xsl:choose>

            <xsl:element name="Value">
                <xsl:apply-templates />
            </xsl:element>
        </xsl:if>
    </xsl:template>

    <!-- ********************************************* RECORD MATCHER ********************************************* -->
    <xsl:template match="record[ancestor::record[@name='sig_in' or @name='sig_out'] and  value[@name = 'field_name']]">
        <!-- XPath to the actual record item -->
        <xsl:param name="path" />

        <!-- Set the new path -->
        <xsl:variable name="newpath">
            <xsl:value-of select="concat($path,'/', value[@name = 'field_name']/text())" />
        </xsl:variable>

        <!-- XSL:ELEMENT to contain nested records within value tags, so we can handle Array&Map types uniformly. -->

        <xsl:copy>
            <xsl:attribute name="path">
                <xsl:value-of select="$newpath" />
            </xsl:attribute>

            <xsl:apply-templates mode="values" select="value" />

            <xsl:apply-templates>
                <xsl:with-param name="path" select="$newpath" />
            </xsl:apply-templates>
        </xsl:copy>

    </xsl:template>

    <xsl:template match="record[@path]">
        <xsl:element name="Value">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    <!-- ********* Match the inputs ********* -->
    <xsl:template match="record[@name='sig_in']">
        <Inputs name="sig_in">
            <xsl:apply-templates>
                <xsl:with-param name="path" select="'sig_in'" />
            </xsl:apply-templates>
        </Inputs>
    </xsl:template>

    <!-- ********* Match the outputs ********* -->
    <xsl:template match="record[@name='sig_out']">
        <Outputs name="sig_out">
            <xsl:apply-templates>
                <xsl:with-param name="path" select="'sig_out'" />
            </xsl:apply-templates>
        </Outputs>
    </xsl:template>

    <!-- *********** Container node for the IO records *********** -->
    <xsl:template match="Values[descendant::record[@name='svc_sig']]">
        <Values name="svc_sig">
            <xsl:apply-templates select="descendant::record[@name='svc_sig']" />
        </Values>
    </xsl:template>

    <!-- *** Process node *** -->
    <xsl:template match="node()">
        <xsl:param name="path" />

        <xsl:apply-templates select="node()">
            <xsl:with-param name="path" select="$path" />
        </xsl:apply-templates>
    </xsl:template>

</xsl:stylesheet>

现在我在以下文档中从java执行此转换:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Values version="2.0">
  <value name="svc_type">flow</value>
  <value name="svc_subtype">default</value>
  <value name="svc_sigtype">java 3.5</value>
  <record javaclass="com.wm.util.Values" name="svc_sig">
    <record javaclass="com.wm.util.Values" name="sig_in">
      <value name="node_type">record</value>
      <value name="is_public">false</value>
      <value name="field_type">record</value>
      <value name="field_dim">0</value>
      <value name="nillable">true</value>
      <value name="form_qualified">false</value>
      <value name="is_global">false</value>
      <array depth="1" name="rec_fields" type="record">
        <record javaclass="com.wm.util.Values">
          <value name="node_type">record</value>
          <value name="node_comment"/>
          <record javaclass="com.wm.util.Values" name="node_hints">
            <value name="field_largerEditor">false</value>
            <value name="field_password">false</value>
          </record>
          <value name="is_public">false</value>
          <value name="field_name">unformatted_email</value>
          <value name="field_type">record</value>
          <value name="field_dim">0</value>
          <value name="nillable">true</value>
          <value name="form_qualified">false</value>
          <value name="is_global">false</value>
          <value name="rec_closed">true</value>
          <value name="modifiable">true</value>
          <value name="rec_ref">t00cc_emailresponder.data:email</value>
        <array depth="1" name="rec_fields" type="record">
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">senders</value>
        <value name="field_type">string</value>
        <value name="field_dim">1</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
        <value name="is_soap_array_encoding_used">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">mailBoxNames</value>
        <value name="field_type">string</value>
        <value name="field_dim">1</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
        <value name="is_soap_array_encoding_used">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <value name="field_usereditable">true</value>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">subject</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <value name="field_usereditable">true</value>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">recvDate</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">body</value>
        <value name="field_type">object</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
    </array>
        </record>
      </array>
      <value name="modifiable">true</value>
    </record>
    <record javaclass="com.wm.util.Values" name="sig_out">
      <value name="node_type">record</value>
      <value name="is_public">false</value>
      <value name="field_type">record</value>
      <value name="field_dim">0</value>
      <value name="nillable">true</value>
      <value name="form_qualified">false</value>
      <value name="is_global">false</value>
      <array depth="1" name="rec_fields" type="record">
        <record javaclass="com.wm.util.Values">
          <value name="node_type">record</value>
          <value name="node_comment"/>
          <record javaclass="com.wm.util.Values" name="node_hints">
            <value name="field_largerEditor">false</value>
            <value name="field_password">false</value>
          </record>
          <value name="is_public">false</value>
          <value name="field_name">formatted_email</value>
          <value name="field_type">record</value>
          <value name="field_dim">0</value>
          <value name="nillable">true</value>
          <value name="form_qualified">false</value>
          <value name="is_global">false</value>
          <value name="rec_closed">true</value>
          <value name="modifiable">true</value>
          <value name="rec_ref">t00cc_emailresponder.data:formatted_email</value>
        <array depth="1" name="rec_fields" type="record">
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">@id</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">sender</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">mailBoxName</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">subject</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">recv_date</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
      <record javaclass="com.wm.util.Values">
        <value name="node_type">record</value>
        <value name="node_comment"/>
        <record javaclass="com.wm.util.Values" name="node_hints">
          <null name="field_usereditable"/>
          <value name="field_largerEditor">false</value>
          <value name="field_password">false</value>
        </record>
        <value name="is_public">false</value>
        <value name="field_name">body</value>
        <value name="field_type">string</value>
        <value name="field_dim">0</value>
        <value name="nillable">true</value>
        <value name="form_qualified">false</value>
        <value name="is_global">false</value>
      </record>
    </array>
        </record>
      </array>
      <value name="modifiable">true</value>
    </record>
  </record>
  <value name="node_comment">Service converts email from transport/email to fomatted email.
Email's sender and receiver will be normalized, unnecessary parts (added by outlook or any other mail client)
will be removed from email address.
Email's sent date will be converted to xml datetimeformat.
Email's body will be mapped from bytestream to string. (convertion happend earlier)

Input:
unformatted_email - type of email

Output:
formatted_email - type of formatted_email - converted, formatted email. Values in this format will be compatible with
waiting format fields of INM web service.
</value>
  <value name="stateless">no</value>
  <value name="caching">no</value>
  <value name="prefetch">no</value>
  <value name="cache_ttl">15</value>
  <value name="prefetch_level">1</value>
  <value name="template">t00cc_emailresponder_functional_mail_formatMailFields</value>
  <value name="template_type">html</value>
  <value name="audit_level">off</value>
  <value name="check_internal_acls">no</value>
  <value name="icontext_policy">$null</value>
  <value name="system_service">no</value>
  <value name="retry_max">0</value>
  <value name="retry_interval">0</value>
  <value name="svc_in_validator_options">none</value>
  <value name="svc_out_validator_options">none</value>
  <value name="auditoption">0</value>
  <null name="auditfields_input"/>
  <null name="auditfields_output"/>
  <record javaclass="com.wm.util.Values" name="auditsettings">
    <value name="document_data">0</value>
    <value name="startExecution">false</value>
    <value name="stopExecution">false</value>
    <value name="onError">true</value>
  </record>
  <value name="pipeline_option">1</value>
  <null name="originURI"/>
  <value name="modifiable">true</value>
  <value name="is_public">false</value>
</Values>

对于输出,XSLT生成以下XML文档:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Values name="svc_sig">
    <Inputs name="sig_in">
        <record path="sig_in/unformatted_email">
            <Name>unformatted_email</Name>
            <Type>RECORD</Type>
            <Depth>SIMPLE</Depth>
            <Value/>
            <record path="sig_in/unformatted_email/senders">
                <Name>senders</Name>
                <Type>string</Type>
                <Depth>ARRAY</Depth>
                <Value>{{NS}}</Value>
            </record>
            <record path="sig_in/unformatted_email/mailBoxNames">
                <Name>mailBoxNames</Name>
                <Type>string</Type>
                <Depth>ARRAY</Depth>
                <Value>{{NS}}</Value>
            </record>
            <record path="sig_in/unformatted_email/subject">
                <Name>subject</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_in/unformatted_email/recvDate">
                <Name>recvDate</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_in/unformatted_email/body">
                <Name>body</Name>
                <Type>object</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
        </record>
    </Inputs>
    <Outputs name="sig_out">
        <record path="sig_out/formatted_email">
            <Name>formatted_email</Name>
            <Type>RECORD</Type>
            <Depth>SIMPLE</Depth>
            <Value/>
            <record path="sig_out/formatted_email/@id">
                <Name>@id</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_out/formatted_email/sender">
                <Name>sender</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_out/formatted_email/mailBoxName">
                <Name>mailBoxName</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_out/formatted_email/subject">
                <Name>subject</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_out/formatted_email/recv_date">
                <Name>recv_date</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
            <record path="sig_out/formatted_email/body">
                <Name>body</Name>
                <Type>string</Type>
                <Depth>SIMPLE</Depth>
                <Value>{NS}</Value>
            </record>
        </record>
    </Outputs>
</Values>

现在,虽然结果看起来确实正确,但只有一个小的“错误”让我发疯。我似乎无法将另一条记录中的嵌套记录移动到Value节点内。意思是,我希望更像以下内容:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Values name="svc_sig">
    <Inputs name="sig_in">
        <record path="sig_in/unformatted_email">
            <Name>unformatted_email</Name>
            <Type>RECORD</Type>
            <Depth>SIMPLE</Depth>
            <Value>
                <record path="sig_in/unformatted_email/senders">
                    <Name>senders</Name>
                    <Type>string</Type>
                    <Depth>ARRAY</Depth>
                    <Value>{{NS}}</Value>
                </record>
                <record path="sig_in/unformatted_email/mailBoxNames">
                    <Name>mailBoxNames</Name>
                    <Type>string</Type>
                    <Depth>ARRAY</Depth>
                    <Value>{{NS}}</Value>
                </record>
                <record path="sig_in/unformatted_email/subject">
                    <Name>subject</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_in/unformatted_email/recvDate">
                    <Name>recvDate</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_in/unformatted_email/body">
                    <Name>body</Name>
                    <Type>object</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
            </Value>
        </record>
    </Inputs>
    <Outputs name="sig_out">
        <record path="sig_out/formatted_email">
            <Name>formatted_email</Name>
            <Type>RECORD</Type>
            <Depth>SIMPLE</Depth>
            <Value>
                <record path="sig_out/formatted_email/@id">
                    <Name>@id</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_out/formatted_email/sender">
                    <Name>sender</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_out/formatted_email/mailBoxName">
                    <Name>mailBoxName</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_out/formatted_email/subject">
                    <Name>subject</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_out/formatted_email/recv_date">
                    <Name>recv_date</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
                <record path="sig_out/formatted_email/body">
                    <Name>body</Name>
                    <Type>string</Type>
                    <Depth>SIMPLE</Depth>
                    <Value>{NS}</Value>
                </record>
            </Value>
        </record>
    </Outputs>
</Values>

更新:   - 任何记录都应包含1个Value节点,其中包含所有字段。因此,将xsl:element应用于模板会将每个单独的字段放入其自己的Value节点,这在当前情况下是“坏的”。问题仍然没有以这种方式发展,即这些记录可以嵌套在彼此内部,每条记录应该只包含一个具有所有类似字段记录的Value节点。

我的第一印象是修改XSLT脚本以创建xsl:元素,因为您可以在上面的XSLT中看到注释,但是这会导致每个记录字段的Value节点,这将假定包含的记录有1字段,实际上是数组。

谢谢,  乔伊

1 个答案:

答案 0 :(得分:1)

她的样式表基于你的一些变化。
 正如我之前所说:如果Record元素应该嵌套在Value元素中,则需要在xsl:apply-templates内使用<xsl:element name="Value">

请试试这个:

<?xml version="1.0" encoding="utf-8" ?>
<!--
** DEV. NOTES:
**  - NOT TESTED YET!
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- *********** Output type definition ************ -->
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:template match="value" mode="values" />


    <xsl:template match="record" mode="values">
        <xsl:param name="path" />
        <xsl:apply-templates select="value" mode="values"/>
        <xsl:variable name ="field_dim" select="value[@name = 'field_dim']/text()" />
        <xsl:choose>
            <xsl:when test="$field_dim = '0'">
                <!-- A simple variable is allowed. -->
                <xsl:element name="Depth">SIMPLE</xsl:element>
                <xsl:element name="Value">
                    <xsl:if test="not(descendant::record[value[@name = 'field_name']])">
                        <xsl:text>{NS}</xsl:text> 
                    </xsl:if>
                    <xsl:apply-templates >
                        <xsl:with-param name="path" select="$path" />
                    </xsl:apply-templates>
                </xsl:element>
            </xsl:when>
            <xsl:when test="$field_dim  = '1'">
                <!-- The parameter has the type of Array<T>. -->
                <xsl:element name="Depth">ARRAY</xsl:element>
                <xsl:element name="Value">{{NS}}</xsl:element>
            </xsl:when>
            <xsl:when test="$field_dim  = '2'">
                <!-- The parameter is some kind of hash table like: java.util.Map<String, Object> -->
                <xsl:element name="Depth">MAP</xsl:element>
                <xsl:element name="Value">
                    <xsl:element name="TKey">{NS}</xsl:element>
                    <xsl:element name="TValue">{NS}</xsl:element>
                </xsl:element>
            </xsl:when>
            <!-- So far no other stuff is allowed. -->
            <xsl:otherwise />
        </xsl:choose>

    </xsl:template>

    <!-- ******************************************* VALUE MATCHER ******************************************** -->
    <xsl:template match="value[@name = 'field_name']" mode="values">
        <!-- Create element for the Name node. -->
        <xsl:element name="Name">
            <xsl:value-of select="text()" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="value[@name = 'field_type']" mode="values">
        <!-- Create element for the Type node. -->
        <xsl:element name="Type">
            <!-- If the type is not a record type. -->
            <xsl:if test="not(text() = 'record')">
                    <xsl:value-of select="text()" />
            </xsl:if>
            <!-- Else if the Type is record type. -->
            <xsl:if test="text() = 'record'">RECORD</xsl:if>
        </xsl:element>
    </xsl:template>



    <!-- ********************************************* RECORD MATCHER ********************************************* -->
    <xsl:template match="record[ancestor::record[@name='sig_in' or @name='sig_out'] and  value[@name = 'field_name']]">
        <!-- XPath to the actual record item -->
        <xsl:param name="path" />

        <!-- Set the new path -->
        <xsl:variable name="newpath">
            <xsl:value-of select="concat($path,'/', value[@name = 'field_name']/text())" />
        </xsl:variable>

        <!-- XSL:ELEMENT to contain nested records withi value tags, so we can handle Array&Map types uniformly. -->

        <xsl:copy>
            <xsl:attribute name="path">
                <xsl:value-of select="$newpath" />
            </xsl:attribute>


            <xsl:apply-templates select="."  mode="values" >
                <xsl:with-param name="path" select="$newpath" />
            </xsl:apply-templates>

        </xsl:copy>

    </xsl:template>

    <!-- ********* Match the inputs ********* -->
    <xsl:template match="record[@name='sig_in']">
        <Inputs name="sig_in">
            <xsl:apply-templates>
                <xsl:with-param name="path" select="'sig_in'" />
            </xsl:apply-templates>
        </Inputs>
    </xsl:template>

    <!-- ********* Match the outputs ********* -->
    <xsl:template match="record[@name='sig_out']">
        <Outputs name="sig_out">
            <xsl:apply-templates>
                <xsl:with-param name="path" select="'sig_out'" />
            </xsl:apply-templates>
        </Outputs>
    </xsl:template>

    <!-- *********** Container node for the IO records *********** -->
    <xsl:template match="Values[descendant::record[@name='svc_sig']]">
        <Values name="svc_sig">
            <xsl:apply-templates select="descendant::record[@name='svc_sig']" />
        </Values>
    </xsl:template>

    <!-- *** Process node *** -->
    <xsl:template match="node()">
        <xsl:param name="path" />

        <xsl:apply-templates select="node()">
            <xsl:with-param name="path" select="$path" />
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

将生成以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<Values name="svc_sig">
  <Inputs name="sig_in">
    <record path="sig_in/unformatted_email">
      <Name>unformatted_email</Name>
      <Type>RECORD</Type>
      <Depth>SIMPLE</Depth>
      <Value>
        <record path="sig_in/unformatted_email/senders">
          <Name>senders</Name>
          <Type>string</Type>
          <Depth>ARRAY</Depth>
          <Value>{{NS}}</Value>
        </record>
        <record path="sig_in/unformatted_email/mailBoxNames">
          <Name>mailBoxNames</Name>
          <Type>string</Type>
          <Depth>ARRAY</Depth>
          <Value>{{NS}}</Value>
        </record>
        <record path="sig_in/unformatted_email/subject">
          <Name>subject</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_in/unformatted_email/recvDate">
          <Name>recvDate</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_in/unformatted_email/body">
          <Name>body</Name>
          <Type>object</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
      </Value>
    </record>
  </Inputs>
  <Outputs name="sig_out">
    <record path="sig_out/formatted_email">
      <Name>formatted_email</Name>
      <Type>RECORD</Type>
      <Depth>SIMPLE</Depth>
      <Value>
        <record path="sig_out/formatted_email/@id">
          <Name>@id</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_out/formatted_email/sender">
          <Name>sender</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_out/formatted_email/mailBoxName">
          <Name>mailBoxName</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_out/formatted_email/subject">
          <Name>subject</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_out/formatted_email/recv_date">
          <Name>recv_date</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
        <record path="sig_out/formatted_email/body">
          <Name>body</Name>
          <Type>string</Type>
          <Depth>SIMPLE</Depth>
          <Value>{NS}</Value>
        </record>
      </Value>
    </record>
  </Outputs>
</Values>

您需要考虑的是以下代码中的值内容的条件:

<xsl:element name="Value">
    <xsl:if test="not(descendant::record[value[@name = 'field_name']])">
        <xsl:text>{NS}</xsl:text> 
    </xsl:if>
    <xsl:apply-templates >
        <xsl:with-param name="path" select="$path" />
    </xsl:apply-templates>
</xsl:element>

如果没有更多带有属性name = field_name的am值的记录,则会生成“{NS}”。否则就会生成记录。