Slightly complex grouping based on node values using XSLT 1.0

谁说我不能喝 提交于 2019-12-25 06:31:11

问题


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:


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>


来源:https://stackoverflow.com/questions/43818999/slightly-complex-grouping-based-on-node-values-using-xslt-1-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!