复杂XML结构的XSLT转换

时间:2018-01-31 10:25:08

标签: xml xslt xslt-2.0

我正在寻找XSLT 2.0使用group by的解决方案。我的挑战是我有一个两级XML复合体,其属性我需要用来将它与另一个节点分组并产生另一个复杂的结构。下面是实际的XML和预期的XML。我是XSLT的新手,没有取得多大进展,即使是方向也会有所帮助。

XML要转换:

<decisionTable xmlns="http:///com/tibco/cep/decision/table/model/DecisionTable.ecore">
    <rule id="1">
        <cond colId="1" expr="R001" id="1_1" />
        <act colId="2" expr="G1" id="1_2" />
        <act colId="3" expr="" id="1_3" />
        <act colId="4" expr="E1.Prop1" id="1_4" />
        <act colId="5" expr="&gt;" id="1_5" />
        <act colId="6" expr="E1.prop2" id="1_6" />
        <act colId="7" expr="1" id="1_7" />
    </rule>
    <rule id="3">
        <cond colId="1" expr="R001" id="3_1" />
        <act colId="2" expr="G1" id="3_2" />
        <act colId="3" expr="" id="3_3" />
        <act colId="4" expr="E1.Prop1" id="3_4" />
        <act colId="5" expr="&gt;" id="3_5" />
        <act colId="6" expr="E1.prop2" id="3_6" />
        <act colId="7" expr="2" id="3_7" />
    </rule>
    <rule id="4">
        <cond colId="1" expr="R001" id="4_1" />
        <act colId="2" expr="G2" id="4_2" />
        <act colId="3" expr="" id="4_3" />
        <act colId="4" expr="E1.prop1" id="4_4" />
        <act colId="5" expr="&gt;" id="4_5" />
        <act colId="6" expr="E1.prop2" id="4_6" />
        <act colId="7" expr="1" id="4_7" />
    </rule>
    <rule id="6">
        <cond colId="1" expr="R001" id="6_1" />
        <act colId="2" expr="G2" id="6_2" />
        <act colId="3" expr="" id="6_3" />
        <act colId="4" expr="E1.prop1" id="6_4" />
        <act colId="5" expr="&gt;" id="6_5" />
        <act colId="6" expr="E1.prop2" id="6_6" />
        <act colId="7" expr="2" id="6_7" />
    </rule>
    <rule id="7">
        <cond colId="1" expr="R002" id="7_1" />
        <act colId="2" expr="G1" id="7_2" />
        <act colId="3" expr="" id="7_3" />
        <act colId="4" expr="E1.prop1" id="7_4" />
        <act colId="5" expr="&gt;" id="7_5" />
        <act colId="6" expr="E1.prop2" id="7_6" />
        <act colId="7" expr="1" id="7_7" />
    </rule>
    <rule id="8">
        <cond colId="1" expr="R003" id="8_1" />
        <act colId="2" expr="G1" id="8_2" />
        <act colId="3" expr="" id="8_3" />
        <act colId="4" expr="E1.prop1" id="8_4" />
        <act colId="5" expr="&gt;" id="8_5" />
        <act colId="6" expr="E1.prop2" id="8_6" />
        <act colId="7" expr="1" id="8_7" />
    </rule>
    <columns>
        <column alias="RuleId" columnType="CONDITION" id="1"
            name="ruleDef.RuleId" propertyPath="/Concepts/RuleDefinitionDTConcept/RuleId" />
        <column alias="GroupName" columnType="ACTION" id="2"
            name="ruleDef.GroupName" propertyPath="/Concepts/RuleDefinitionDTConcept/GroupName" />
        <column alias="Action" columnType="ACTION" id="3" name="ruleDef.Action"
            propertyPath="/Concepts/RuleDefinitionDTConcept/Action" />
        <column alias="LValue" columnType="ACTION" id="4" name="ruleDef.LValue"
            propertyPath="/Concepts/RuleDefinitionDTConcept/LValue" />
        <column alias="Operator" columnType="ACTION" id="5"
            name="ruleDef.Operator" propertyPath="/Concepts/RuleDefinitionDTConcept/Operator" />
        <column alias="RValue" columnType="ACTION" id="6" name="ruleDef.RValue"
            propertyPath="/Concepts/RuleDefinitionDTConcept/RValue" />
        <column alias="SequenceNo" columnType="ACTION" id="7"
            name="ruleDef.SequenceNo" propertyPath="/Concepts/RuleDefinitionDTConcept/SequenceNo"
            propertyType="1" />
    </columns>
</decisionTable>

预期产出

<?xml version="1.0" encoding="UTF-8"?>
<RuleId>
    <RuleIdVal>ROO1</RuleIdVal>
    <Group>
        <Name>G1</Name>
        <EventRule>
            <Sequence>1</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
        <EventRule>
            <Sequence>2</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
    </Group>
    <Group>
        <Name>G2</Name>
        <EventRule>
            <Sequence>1</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
        <EventRule>
            <Sequence>2</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
    </Group>
</RuleId>
<RuleId>
    <RuleIdVal>ROO2</RuleIdVal>
    <Group>
        <Name>G1</Name>
        <EventRule>
            <Sequence>1</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
    </Group>
</RuleId>
<RuleId>
    <RuleIdVal>ROO3</RuleIdVal>
    <Group>
        <Name>G1</Name>
        <EventRule>
            <Sequence>1</Sequence>
            <LValue>E1.Prop1</LValue>
            <Operator>&gt;</Operator>
            <Rvalue>E1.Prop2</Rvalue>
            <Action></Action>
            <Status></Status>
        </EventRule>
    </Group>
</RuleId>

谢谢,

2 个答案:

答案 0 :(得分:2)

您需要使用嵌套循环来获取输出结构。外部循环必须按RuleId值分组,即R00X

<xsl:for-each-group select="dt:rule" group-by="dt:cond[@colId = '1']/@expr">

然后使用内部循环对Group Name进行分组,即GX

<xsl:for-each-group select="current-group()" group-by="dt:act[@colId = '2']/@expr" >

最后是另一个内部循环,用于从当前组中提取<EventRule>下的元素。

<xsl:for-each select="current-group()">

完整的XSLT如下所示

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dt="http:///com/tibco/cep/decision/table/model/DecisionTable.ecore"
    exclude-result-prefixes="dt">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="dt:decisionTable">
        <!-- outer loop to group by using rule id -->
        <xsl:for-each-group select="dt:rule" group-by="dt:cond[@colId = '1']/@expr">
            <RuleId>
                <RuleIdVal><xsl:value-of select="current-grouping-key()" /></RuleIdVal>
                <!-- inner loop to group by using group name -->
                <xsl:for-each-group select="current-group()" group-by="dt:act[@colId = '2']/@expr" >
                    <Group>
                        <Name><xsl:value-of select="current-grouping-key()" /></Name>
                        <!-- loop to get remaining values -->
                        <xsl:for-each select="current-group()">
                            <EventRule>
                                <Sequence><xsl:value-of select="dt:act[@colId = '7']/@expr" /></Sequence>
                                <LValue><xsl:value-of select="dt:act[@colId = '4']/@expr" /></LValue>
                                <Operator><xsl:value-of select="dt:act[@colId = '5']/@expr" /></Operator>
                                <RValue><xsl:value-of select="dt:act[@colId = '6']/@expr" /></RValue>
                                <Action><xsl:value-of select="dt:act[@colId = '3']/@expr" /></Action>
                                <Status></Status>
                            </EventRule>
                        </xsl:for-each>
                    </Group>
                </xsl:for-each-group>
            </RuleId>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

产生所需的输出

<RuleId>
   <RuleIdVal>R001</RuleIdVal>
   <Group>
      <Name>G1</Name>
      <EventRule>
         <Sequence>1</Sequence>
         <LValue>E1.Prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
      <EventRule>
         <Sequence>2</Sequence>
         <LValue>E1.Prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
   </Group>
   <Group>
      <Name>G2</Name>
      <EventRule>
         <Sequence>1</Sequence>
         <LValue>E1.prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
      <EventRule>
         <Sequence>2</Sequence>
         <LValue>E1.prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
   </Group>
</RuleId>
<RuleId>
   <RuleIdVal>R002</RuleIdVal>
   <Group>
      <Name>G1</Name>
      <EventRule>
         <Sequence>1</Sequence>
         <LValue>E1.prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
   </Group>
</RuleId>
<RuleId>
   <RuleIdVal>R003</RuleIdVal>
   <Group>
      <Name>G1</Name>
      <EventRule>
         <Sequence>1</Sequence>
         <LValue>E1.prop1</LValue>
         <Operator>&gt;</Operator>
         <RValue>E1.prop2</RValue>
         <Action/>
         <Status/>
      </EventRule>
   </Group>
</RuleId>

答案 1 :(得分:0)

在我看来,可以使用以下方式实现分组:

<xsl:stylesheet ....
   xmlns:d="http:///com/tibco/cep/decision/table/model/DecisionTable.ecore"    
   exclude-result-prefixes="d">

<xsl:template match="d:decisionTable">
  <RuleId>
    <xsl:for-each-group select="d:rule" group-by="d:act[1]/expr">
       <Group>
         <Name><xsl:value-of select="current-grouping-key()"/></Name>
         <xsl:apply-templates select="current-group()"/>
       </Group>
   </xsl:for-each-group>
 </RuleId>
</xsl:template>

这里还有一些其他的东西,最后的“columns”元素似乎是输出中输入到列名的元数据映射列号;我不清楚它扮演的角色是什么,但它似乎是一个与分组完全不同的问题。