问题
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:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<row>
<ISSUEID>I6</ISSUEID>
<ISSUEBA>MEDICAID</ISSUEBA>
<OBJECTID>10</OBJECTID>
<OBJECTBA>MEDICAID</OBJECTBA>
</row>
<row>
<CASEID>C11</CASEID>
<CASEBA>MEDICAID</CASEBA>
<OBJECTID>11</OBJECTID>
<OBJECTBA>MEDICAID</OBJECTBA>
</row>
</results>
I have to transform the above xml to simpler one using XSLT by following the below conditions:
If I have the
<CASEID>
, then<CASE>
tag should be there. If I have the<ISSUEID>
, then<ISSUE>
tag should be there. If I have the<OBJECT>
, then<OBJECTID>
tag should be there. The reason behind this is some of the row elements might have<CASEID>
<ISSUEID>
<OBJECTID>
and some not. A<CASE>
can directly have a<SOURCE>
under it if there is no<ISSUE>
.
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>
<ISSUE>
<ISSUEID>I6</ISSUEID>
<ISSUEBA>MEDICAID</ISSUEBA>
<SOURCE>
<OBJECTID>10</OBJECTID>
<OBJECTBA>MEDICAID</OBJECTBA>
</SOURCE>
</ISSUE>
<CASE>
<CASEID>C11</CASEID>
<CASEBA>MEDICAID</CASEBA>
<SOURCE>
<OBJECTID>11</OBJECTID>
<OBJECTBA>MEDICAID</OBJECTBA>
</SOURCE>
</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:
You can still solve this using Muenchian Grouping. If you are grouping by CASEID
initially, but CASEID
may not be present, you can define the first key like so
<xsl:key name="case" match="row" use="string(CASEID)" />
So, for the first key, row
elements with no CASEID
will be matched by an empty string and grouped together.
To group by INDEXID
within CASEID
, you can use a key like this, as this will still work with no CASEID
(as concat
returns a string)
<xsl:key name="issue" match="row" use="concat(CASEID, '|', ISSUEID)" />
To select the distinct CASEID
records you would then do this:
<xsl:apply-templates select="row[generate-id() = generate-id(key('case', string(CASEID))[1])]" mode="case" />
However, in the template that matched the row
elements for this mode, you would need a xsl:choose
statement, to check whether CASEID
existed or not. If they did exist, you would create <CASE>
element. If not, you would apply the next level key.
<xsl:choose>
<xsl:when test="CASEID">
<CASE>
<!-- Apply next key -->
</CASE>
</xsl:when>
<xsl:otherwise>
<!-- Apply next key -->
</xsl:otherwise>
</xsl:choose>
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="string(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', string(CASEID))[1])]" mode="case" />
</xsl:copy>
</xsl:template>
<xsl:template match="row" mode="case">
<xsl:choose>
<xsl:when test="CASEID">
<CASE>
<xsl:apply-templates select="CASEID|CASEBA" />
<xsl:apply-templates select="key('case', string(CASEID))[generate-id() = generate-id(key('issue', concat(CASEID, '|', ISSUEID))[1])]" mode="issue" />
</CASE>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="key('case', concat('', CASEID))[generate-id() = generate-id(key('issue', concat(CASEID, '|', ISSUEID))[1])]" mode="issue" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="row" mode="issue">
<xsl:choose>
<xsl:when test="ISSUEID">
<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:when>
<xsl:otherwise>
<xsl:apply-templates select="key('issue', concat(CASEID, '|', ISSUEID))[generate-id() = generate-id(key('object', concat(CASEID, '|', ISSUEID, '|', OBJECTID))[1])]" mode="object" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="row" mode="object">
<xsl:if test="OBJECTID">
<SOURCE>
<xsl:apply-templates select="OBJECTID|OBJECTBA" />
</SOURCE>
</xsl:if>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
来源:https://stackoverflow.com/questions/43820145/grouping-based-on-the-node-value-if-only-it-exists-using-xslt-1-0