Picking unique heads

2019-08-26 11:19发布

I some XML that is already ordered and grouped by categories. So, I was thinking of using XSLT 1.0 grouping to pull out the category heads. But I was wondering if there is an easier way to simply pick the first heading of each category and group and delete or ignore the duplicates.

Here is a sample of the XML:

<dataroot>
  <CaseStudies>
    <category>1</category>
    <GroupNo>2</GroupNo>
    <H1>Evaluation and Management</H1>
    <H2>Office or Other Outpatient Services</H2>
    <H3>New Patient</H3>
    <indicators>{+}</indicators>
    <code>99201</code>
    <Fulldesc>Office or other outpatient.</Fulldesc>
    <HTMLdesc>
      <b>Office or other outpatient visit.</b>
    </HTMLdesc>
    <GlobalPeriod>XXX</GlobalPeriod>
    <assist_ref>CPT Assistant Winter</assist_ref>
    <changes_ref>CPT Changes: An Insider&apos;s View 2011, 2013</changes_ref>
    <case_study>Initial office visit.</case_study>
    <pre>Review the medical history.</pre>
    <intra>Obtain a problem focused history.</intra>
    <post>Complete medical record documentation.</post>
    <tip>Levels of E/M service.</tip>
  </CaseStudies>
  <CaseStudies>
    <category>1</category>
    <GroupNo>2</GroupNo>
    <H1>Evaluation and Management</H1>
    <H2>Office or Other Outpatient Services</H2>
    <H3>Established Patient</H3>
    <indicators>{+}</indicators>
    <code>99202</code>
    <Fulldesc>Office or other outpatient visit f.</Fulldesc>
    <HTMLdesc>
      <b>Office or other outpatient visit.</b>
    </HTMLdesc>
    <GlobalPeriod>XXX</GlobalPeriod>
    <assist_ref>CPT Assistant Winter 91:11</assist_ref>
    <changes_ref>CPT Changes</changes_ref>
    <case_study>Initial office visit.</case_study>
    <pre>Review the medical history.</pre>
    <intra>Obtain an expanded problem.</intra>
    <post>Complete medical record documentation.</post>
    <tip>pending proof</tip>
  </CaseStudies>
  <CaseStudies>
    <category>1</category>
    <GroupNo>3</GroupNo>
    <H1>Anesthesia</H1>
    <H2>Intrathoracic</H2>
    <H3>New Patient</H3>
    <indicators>{+}</indicators>
    <code>99203</code>
    <Fulldesc>Office or other outpatient visit.</Fulldesc>
    <HTMLdesc>
      <b>Office or other outpatient visit.</b>
    </HTMLdesc>
    <GlobalPeriod>XXX</GlobalPeriod>
    <assist_ref>CPT Assistant Winter 91:11</assist_ref>
    <changes_ref>CPT Changes: An Insider&apos;s View 2013</changes_ref>
    <case_study>Initial office visit.</case_study>
    <pre>Review the medical history form completed by the patient and vital signs obtained by clinical staff. Communicate with other health care professionals as necessary.</pre>
    <intra>Obtain a detailed history.</intra>
    <post>Complete medical record documentation.</post>
    <tip>pending proof</tip>
  </CaseStudies>
  <CaseStudies>
    <category>1</category>
    <GroupNo>3</GroupNo>
    <H1>Anesthesia</H1>
    <H2>Intrathoracic</H2>
    <H3>Established Patient</H3>
    <indicators>{+}</indicators>
    <code>99203</code>
    <Fulldesc>Office or other outpatient visit.</Fulldesc>
    <HTMLdesc>
      <b>Office or other outpatient visit.</b>
    </HTMLdesc>
    <GlobalPeriod>XXX</GlobalPeriod>
    <assist_ref>CPT Assistant Winter 91:11</assist_ref>
    <changes_ref>CPT Changes: An Insider&apos;s View 2013</changes_ref>
    <case_study>Initial office visit.</case_study>
    <pre>Review the medical history form completed by the patient and vital signs obtained by clinical staff. Communicate with other health care professionals as necessary.</pre>
    <intra>Obtain a detailed history.</post>
    <tip>pending proof</tip>
  </CaseStudies>
</dataroot>

Notice there are h1, h2, and h3 heads in my sample but there can also be h4, h5 and h6 heads too.

So, I want to return the content as is but only display each UNIQUE HEAD h1-h6 only once the first time it appears within each section governed by each of the h1, h2, h3, etc.

H1 Surgery
  h2 Hospital Inpatient Services
    h3 Subsequent Observation Care
      h4 New Patient
      h4 Existing Patient
h1 Opthamology
  h2 Hospital Observation Services
    h3 Subsequent Observation Care
      h4 New Patient
      h4 Existing Patient
      h4 Subsequent Hospital Care
h1 Anesthesia
  h2 Hospital Observation Services
    h3 Subsequent Observation Care
      h4 New Patient
      h4 Existing Patient
      h4 Subsequent Hospital Care

Can this be done without creating a group and key?

I have to use XSLT 1.0

2条回答
我命由我不由天
2楼-- · 2019-08-26 11:37

Here's a method that does use a key to retain only unique headings. A heading is considered unique if it is the first of a group of headings grouped by the concatenation of: (1) the element name, (2) the category child of the parent CaseStudies element, and (3) the value.

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="h" match="H1|H2|H3|H4|H5|H6" use="concat(name(), '|', ../category, '|', .)" />

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="H1|H2|H3|H4|H5|H6">
    <xsl:if test="count(. | key('h', concat(name(), '|', ../category, '|', .))[1]) = 1">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

When applied to a simplified and corrected version of your input example:

<dataroot>
   <CaseStudies>
      <category>1</category>
      <H1>Evaluation and Management</H1>
      <H2>Office or Other Outpatient Services</H2>
      <H3>New Patient</H3>
   </CaseStudies>
   <CaseStudies>
      <category>1</category>
      <H1>Evaluation and Management</H1>
      <H2>Office or Other Outpatient Services</H2>
      <H3>Established Patient</H3>
    </CaseStudies>
   <CaseStudies>
      <category>1</category>
      <H1>Anesthesia</H1>
      <H2>Intrathoracic</H2>
      <H3>New Patient</H3>
   </CaseStudies>
   <CaseStudies>
      <category>1</category>
      <H1>Anesthesia</H1>
      <H2>Intrathoracic</H2>
      <H3>Established Patient</H3>
   </CaseStudies>
</dataroot>

the following result is obtained:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot>
   <CaseStudies>
      <category>1</category>
      <H1>Evaluation and Management</H1>
      <H2>Office or Other Outpatient Services</H2>
      <H3>New Patient</H3>
   </CaseStudies>
   <CaseStudies>
      <category>1</category>
      <H3>Established Patient</H3>
   </CaseStudies>
   <CaseStudies>
      <category>1</category>
      <H1>Anesthesia</H1>
      <H2>Intrathoracic</H2>
   </CaseStudies>
   <CaseStudies>
      <category>1</category>
   </CaseStudies>
</dataroot>
查看更多
姐就是有狂的资本
3楼-- · 2019-08-26 11:37

In this case, since the input is always in sensible order, all you really have to do is compare the value of each H* element to the value of the same named element in the immediately-preceding CaseStudies element, and suppress any that are the same.

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

  <xsl:template match="@*|node()" name="ident">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="H1|H2|H3|H4|H5|H6">
    <xsl:if test="not(. = ../preceding-sibling::*[1]/*[name() = name(current())])">
      <xsl:call-template name="ident" />
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Note I'm using not(x = y) instead of x != y to allow for the fact that there might not be a ../preceding-sibling::*[1] at all.

查看更多
登录 后发表回答