【发布时间】:2013-05-22 10:28:02
【问题描述】:
我有一个 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 个值节点,其中包含所有字段。因此,将 xsl:element 应用于应用模板会将值放置到其自己的值节点中,这在当前情况下是“坏的”。问题还没有演变成这些记录可以相互嵌套任何深度,并且每条记录应该只包含一个 Value 节点及其所有类似字段的记录。
我的第一印象是修改 XSLT 脚本以创建一个 xsl:element,正如您在上面 XSLT 中看到的注释一样,但这会导致每个记录字段都有一个 Value 节点,假设包含的记录有 1字段,实际上是在数组中。
谢谢, 乔伊
【问题讨论】:
-
您真的认为保持旧问题开放,不告诉给定答案有什么问题并创建新答案有帮助吗? *.com/q/16413367/2115381
-
如果 Record 元素应该嵌套在 Value 元素中,您需要在
<xsl:element name="Value">中使用xsl:apply-templates -
绝对不是。当前的解决方案没有任何问题,几乎不可能按照当前应用程序中的处理方式进行处理。我已经尝试过这个解决方案,但我还是不够清楚。我会用完整的例子更新问题。
标签: xslt