Search code examples
xmlxsltxquery

Translate XSLT to XQuery


I have document diagnosis.xml

<diagnosis>
  <component name="heart attack" classCode="healthcare service">
    <component name="Diabetes I" classCode="observation" spec="intraocular lens">
      <component name="Diabetes II" classCode="manifestation">
        <component name="Diabetic Retinopathy" classCode="RSON :: rational service" spec="generalized obesity"/>
      </component>
      <component name="Coronary Artery Disease" classCode="ACT :: healthcare service" spec="hypertension"/>
    </component>
    <component name="nonproliferative diabetic retinopathy" classCode="ACT">
      <component name="Ophthalmic diagnosis" classCode="OBS observation" spec="Viscoelastic applied"/>
    </component>
  </component>
  <component name="Extracapsular cataract removal" classCode="PCPR :: care provision">
    <component name="intraocular lens" classCode="Allopathic & Osteopathic" spec="Diabetes I">
      <component name="Viscoelastic applied" classCode="SBADM :: substance administration" spec="Ophthalmic diagnosis"/>
    </component>
    <component name="lipoprotein cholesterol " classCode="BATTERY">
      <component name="Furosemide" classCode="SBADM :: substance administration"/>
      <component name="hypertension" classCode="OBS" spec="Coronary Artery Disease">
        <component name="generalized obesity" classCode="observation" spec="Diabetic Retinopathy"/>
      </component>
    </component>
  </component>
</diagnosis>

In order to discover the intricacy between name and spec(similar to PK-FK in RDBMS), I have diagnosis-q1-q4.xsl

<xsl:template match="diagnosis">
        <xsl:variable name="q"  select="//component"/>
        <result>
            <!-- for each q3 -->
            <xsl:for-each select="$q[../../../component]">
                <!-- get quartile/Q1  -->
                <quartile Q1="{../../@name}" Q3="{@name}"/>
                <!-- get quartile/Q1-spec if quartile/Q1's spec exists -->
                <xsl:if test="../../@spec">
                    <dup q1-spec="{../../@spec}" q3="{@name}"/>
                </xsl:if>
                <!-- get parent's spec of this component  --> 
                <xsl:variable name="q2" select="../@spec"/>
                <!-- get parent of q2 if exists -->
                <xsl:variable name="q3" select="$q[component/@name=$q2]"/>
                <xsl:if test="$q3">
                    <dup q2-spec="{$q3/@name}" q3="{@name}"/>
                    <xsl:if test="$q3/@spec">
                        <dup q3-spec="{$q3/@spec}" q3="{@name}"/>
                    </xsl:if>
                </xsl:if>
            </xsl:for-each>
        </result>
</xsl:template>
    
</xsl:stylesheet>

diagnosis-q1-q4.xsl equivalent is diagnosis-q1-q4.xqy:

xquery version "1.0-ml";
<Lineage>
{
  for $gp in doc("diagnosis.xml")//component,
      $p in $gp/component, 
      $gc in $p/component
  return
    if (exists($gp/@spec))
    then (<quartile Q1="{ $gp/@name }" Q3="{ $gc/@name }"/>,
          <quartile-spec Q1-spec="{ $gp/@spec }" q3="{ $gc/@name }"/>)
    else (<quartile Q1="{ $gp/@name }" Q3="{ $gc/@name }"/>)
}
{
  for $gp in doc("diagnosis.xml")//component,
      $p in $gp/component[@spec != ''], 
      $gc in $p/component 
  return
    let $p-spec := $p/@spec
    for $p-node in doc("diagnosis.xml")//component
    where every $andante in $p-node/@name
    satisfies ($andante = $p-spec)
    return
      if (exists($p-node/../@spec))
        then (<quartile-spec q2-spec-Q1="{ $p-node/../@name }" q3="{ $gc/@name }"/>,
              <quartile-spec q2-spec-Q1-spec="{ $p-node/../@spec }" q3="{ $gc/@name }"/>)
         else (<quartile-spec q2-spec-Q1-="{ $p-node/../@name }" q3="{ $gc/@name }"/>)
}
</Lineage>
Either diagnosis-q1-q4.xsl or diagnosis-q1-q4.xqy yields the same result:
  • Eight pairs: Immediate gp(Q1):: gc(Q3)
  • One pair: gp-spec (Q1-spec) :: gc(q3)
  • Four pairs: parent of parent’s spec(q2-spec-Q1) :: gc(q3)
  • One pair: spec of q2-spec-Q1 (q2-spec-Q1-spec) :: gc(q3)
<Lineage>
   <quartile Q1="heart attack" Q3="Diabetes II"/>
   <quartile Q1="heart attack" Q3="Coronary Artery Disease"/>
   <quartile Q1="heart attack" Q3="Ophthalmic diagnosis"/>
   <quartile Q1="Diabetes I" Q3="Diabetic Retinopathy"/>
   <quartile-spec Q1-spec="intraocular lens" q3="Diabetic Retinopathy"/>
   <quartile Q1="Extracapsular cataract removal" Q3="Viscoelastic applied"/>
   <quartile Q1="Extracapsular cataract removal" Q3="Furosemide"/>
   <quartile Q1="Extracapsular cataract removal" Q3="hypertension"/>
   <quartile Q1="lipoprotein cholesterol " Q3="generalized obesity"/>
   <quartile-spec q2-spec-Q1-="Extracapsular cataract removal" q3="Diabetes II"/>
   <quartile-spec q2-spec-Q1-="Extracapsular cataract removal"
                  q3="Coronary Artery Disease"/>
   <quartile-spec q2-spec-Q1-="heart attack" q3="Viscoelastic applied"/>
   <quartile-spec q2-spec-Q1="Diabetes I" q3="generalized obesity"/>
   <quartile-spec q2-spec-Q1-spec="intraocular lens" q3="generalized obesity"/>
</Lineage>

My questions are:

  1. Is it possible to simplify diagnosis-q1-q4.xqy ?
  2. Is it possible to simplify diagnosis-q1-q4.xsl with XSLT 3.0 ?

Solution

  • From what I understand you wanted to see how to turn XSLT into xquery. So I tried to stay as close as possible to the original stylesheet you provided.

    xquery version "3.1";
    
    let $doc := doc("diagnosis.xml")
    let $q := $doc//component
    
    for $c in $q[../../../component]
    return (
        <quartile Q1="{$c/../../@name}" Q3="{$c/@name}"/>
        ,
        if (exists($c/../../@spec))
        then <dup q1-spec="{$c/../../@spec}" q3="{$c/@name}"/>
        else ()
        ,
        let $q2 := $c/../@spec
        let $q3 := $q[component/@name=$q2]
        return (
            if (exists($q3))
            then (
                <dup q2-spec="{$q3/@name}" q3="{$c/@name}"/>
                ,
                if (exists($q3/@spec))
                then <dup q3-spec="{$q3/@spec}" q3="{$c/@name}"/>
                else ()
            )
            else ()
        )
    )
    

    I also liked the original approach, since it iterates only once over all matching components.

    Hope it sheds some light in the relationship of the two.