0

I have an XSLT stylesheet, that looks basically like:

<?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>

Now I execute this transformation from java on the following document:

<?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>

For output the XSLT generates the following XML document:

<?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>

Now, while the result actually looks correct, there is only one minor "bug" which drives me crazy. I just can't seem to have the nested records within another record to move inside the Value node. Meaning, I'd expect something more like the following:

<?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>

UPDATE: - Any record should contain 1 Value node, with all of its fields inside it. So putting xsl:element to apply templates would values to put each individual field to its own Value node which is "bad" in the current situation. The question still haven't evolved in that manner that these records can be nested any deep inside each other, and each record should contain only one Value node with all of its field-like records.

My first impression was to modify the XSLT script to create an xsl:element as you can see the comment in the above XSLT, but that resulted in a Value node for each record field, which would assume that the containing record has 1 field and is actually in array.

Thanks, Joey

4

1 回答 1

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>

你要考虑的是下面代码中Value内容的条件:

<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}”,否则生成记录。

于 2013-05-23T08:33:07.217 回答