Slightly complex grouping based on node values usi

2019-09-14 18:21发布

My requirement is slightly complex one.I have to use only XSLT 1.0. I could able to get the solution using XSLT 2.0, but I need the solution using 1.0.

I have the following input xml:

<results>
       <row>
          <CASEID>C1</CASEID>
          <CASEBA>MEDICAID</CASEBA>
          <ISSUEID>I1</ISSUEID>
          <ISSUEBA>MEDICAID</ISSUEBA>
          <OBJECTID>1</OBJECTID>
          <OBJECTBA>MEDICAID</OBJECTBA>
       </row>
       <row>
          <CASEID>C1</CASEID>
          <CASEBA>MEDICAID</CASEBA>
          <ISSUEID>I2</ISSUEID>
          <ISSUEBA>MEDICAID</ISSUEBA>
          <OBJECTID>2</OBJECTID>
          <OBJECTBA>MEDICAID</OBJECTBA>
       </row>
       <row>
          <CASEID>C1</CASEID>
          <CASEBA>MEDICAID</CASEBA>
          <ISSUEID>I1</ISSUEID>
          <ISSUEBA>MEDICAID</ISSUEBA>
          <OBJECTID>extra</OBJECTID>
          <OBJECTBA>MEDICAID</OBJECTBA>
       </row>
       <row>
          <CASEID>C2</CASEID>
          <CASEBA>MEDICAID</CASEBA>
          <ISSUEID>I3</ISSUEID>
          <ISSUEBA>MEDICAID</ISSUEBA>
          <OBJECTID>3</OBJECTID>
          <OBJECTBA>MEDICAID</OBJECTBA>
       </row>
    </results>

I have to transform the above xml to simpler one using XSLT by following the below conditions:

1)First target is to move all the <CASEID>'s whose values are same under the new <CASE> tag along with <CASEBA> node.

For Example:

<CASE>
   <CASEID>C1</CASEID>
   <CASEBA>MEDICAID</CASEBA>
</CASE>

2)List out all the <ISSUEID> &<ISSUEBA> whose <CASEID>'s are equal in different <row>'s and move them under the new tag<ISSUE> within the recently created <CASE> tag.

For example:

 <CASE>
     <CASEID>C1</CASEID>
     <CASEBA>MEDICAID</CASEBA>
     <ISSUE>
        <ISSUEID>I1</ISSUEID>
        <ISSUEBA>MEDICAID</ISSUEBA>
     </ISSUE>
     <ISSUE>
        <ISSUEID>I2</ISSUEID>
        <ISSUEBA>MEDICAID</ISSUEBA>
     </ISSUE>
  </CASE>

3)List out all the <OBJECTID>'s whose <ISSUEID>'s are equal in different <row>'s and move them under the new <SOURCE> tag within <ISSUE>tag which will be definitely under the <CASE> . For example:

<CASE>
         <CASEID>C1</CASEID>
         <CASEBA>MEDICAID</CASEBA>
         <ISSUE>
            <ISSUEID>I1</ISSUEID>
            <ISSUEBA>MEDICAID</ISSUEBA>
            <SOURCE>
               <OBJECTID>1</OBJECTID>
               <OBJECTBA>MEDICAID</OBJECTBA>
            </SOURCE>
            <SOURCE>
               <OBJECTID>extra</OBJECTID>
                <OBJECTBA>MEDICAID</OBJECTBA>
            </SOURCE>
         </ISSUE>
         <ISSUE>
            <ISSUEID>I2</ISSUEID>
            <ISSUEBA>MEDICAID</ISSUEBA>
            <SOURCE>
               <OBJECTID>2</OBJECTID>
               <OBJECTBA>MEDICAID</OBJECTBA>
            </SOURCE>
         </ISSUE>
      </CASE>

The final output xml should be as below:

<?xml version="1.0" encoding="UTF-8"?>

  <results>
   <CASE>
      <CASEID>C1</CASEID>
      <CASEBA>MEDICAID</CASEBA>
      <ISSUE>
         <ISSUEID>I1</ISSUEID>
         <ISSUEBA>MEDICAID</ISSUEBA>
         <SOURCE>
            <OBJECTID>1</OBJECTID>
            <OBJECTBA>MEDICAID</OBJECTBA>
         </SOURCE>
         <SOURCE>
            <OBJECTID>extra</OBJECTID>
            <OBJECTBA>MEDICAID</OBJECTBA>
         </SOURCE>
      </ISSUE>
      <ISSUE>
         <ISSUEID>I2</ISSUEID>
         <ISSUEBA>MEDICAID</ISSUEBA>
         <SOURCE>
            <OBJECTID>2</OBJECTID>
            <OBJECTBA>MEDICAID</OBJECTBA>
         </SOURCE>
      </ISSUE>
   </CASE>
   <CASE>
      <CASEID>C2</CASEID>
      <CASEBA>MEDICAID</CASEBA>
      <ISSUE>
         <ISSUEID>I3</ISSUEID>
         <ISSUEBA>MEDICAID</ISSUEBA>
         <SOURCE>
            <OBJECTID>3</OBJECTID>
            <OBJECTBA>MEDICAID</OBJECTBA>
         </SOURCE>
      </ISSUE>
   </CASE>
</results>

Please forgive me if I didn't explain my requirement properly. Please do ask me if you need any additional information. It would be really great if someone helps me out.

1条回答
乱世女痞
2楼-- · 2019-09-14 18:56

In your previous question (Transforming xml based on node values) the answer mentioned about using a technique called Muenchian Grouping in XSLT 1.0. In your case, you have nested grouping. You first group by CASEID, then group by CASEID and ISSUEID, and then finally by CASEID, ISSUEID and OBJECTID

This means defining three keys

<xsl:key name="case" match="row" use="CASEID" />
<xsl:key name="issue" match="row" use="concat(CASEID, '|', ISSUEID)" />
<xsl:key name="object" match="row" use="concat(CASEID, '|', ISSUEID, '|', OBJECTID)" />

To group by CASEID you would select the first element of each group like so

<xsl:apply-templates select="row[generate-id() = generate-id(key('case', CASEID)[1])]" mode="case" />

(I am using mode here because the final XSLT will have multiple templates matching row so you need to distinguish between them).

In the matching template, to then group by ISSUEID within the distinct CASEID values, you would do this.

<xsl:apply-templates select="key('case', CASEID)[generate-id() = generate-id(key('issue', concat(CASEID, '|', ISSUEID))[1])]" mode="issue" />

You would then do similar to group by OBJECTID in the other template.

Try this XSLT

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

    <xsl:key name="case" match="row" use="CASEID" />
    <xsl:key name="issue" match="row" use="concat(CASEID, '|', ISSUEID)" />
    <xsl:key name="object" match="row" use="concat(CASEID, '|', ISSUEID, '|', OBJECTID)" />

    <xsl:template match="results">
        <xsl:copy>
            <xsl:apply-templates select="row[generate-id() = generate-id(key('case', CASEID)[1])]" mode="case" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="row" mode="case">
        <CASE>
            <xsl:apply-templates select="CASEID|CASEBA" />
            <xsl:apply-templates select="key('case', CASEID)[generate-id() = generate-id(key('issue', concat(CASEID, '|', ISSUEID))[1])]" mode="issue" />
        </CASE>
    </xsl:template>

    <xsl:template match="row" mode="issue">
        <ISSUE>
            <xsl:apply-templates select="ISSUEID|ISSUEBA" />
            <xsl:apply-templates select="key('issue', concat(CASEID, '|', ISSUEID))[generate-id() = generate-id(key('object', concat(CASEID, '|', ISSUEID, '|', OBJECTID))[1])]" mode="object" />
        </ISSUE>
    </xsl:template>

    <xsl:template match="row" mode="object">
        <OBJECT>
            <xsl:apply-templates select="OBJECTID|OBJECTBA" />
        </OBJECT>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
查看更多
登录 后发表回答