Search code examples
xslt-2.0xslt-3.0

How to get distinct values from different xpaths in xslt


I would like to achieve distinct values from the given input file using xslt

here is my input:

<Records count="1">
<Record contentId="2410630" levelId="442" levelGuid="29c1b6a4-b7db-49dc-a703-e78aa1b1246a" moduleId="875" parentId="0">
    <Record contentId="2410631" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0">
        <Record contentId="2208294" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0">
            <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Unauthorized modification of Information/System - External</Field>
            <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208294</Field>
            <Field  guid="7de0f37f-765a-4480-bbea-da1638ab3296">Cyber - 1</Field>
            <Field guid="001a8562-9091-4e42-b96a-d17c33c19f6f" >Is all software that will be used for this initiative currently approved for use within</Field>
        </Record>
    </Record>
    <Record contentId="2410632" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0">
        <Record contentId="2208289" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0">
            <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Inadequate Information Security Practices</Field>
            <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208289</Field>
            <Field id="41131" guid="7de0f37f-765a-4480-bbea-da1638ab3296" type="1">Cyber - 10</Field>
            <Field id="41132" guid="001a8562-9091-4e42-b96a-d17c33c19f6f" type="1">Will there be a requirement to connect a 3rd party to xxxxx network and what would be the purpose of this connection?</Field>
        </Record>
    </Record>
    <Record contentId="2410633" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0">
        <Record contentId="2208270" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0">
            <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Loss of Systems Including Data Center</Field>
            <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208270</Field>
            <Field id="41131" guid="7de0f37f-765a-4480-bbea-da1638ab3296" type="1">Cyber - 11</Field>
            <Field id="41132" guid="001a8562-9091-4e42-b96a-d17c33c19f6f" type="1">Is this product or service hosted or recovered </Field>
        </Record>   
    </Record>
    <Record contentId="2410636" levelId="458" levelGuid="67dbf848-5352-4953-a25b-1b1bbcde89be" moduleId="891" parentId="0">
        <Record contentId="2208289" levelId="330" levelGuid="d25cfb04-eb2a-423c-bdab-2db21a58fd4d" moduleId="675" parentId="0">
            <Field id="31799" guid="2ebbfd8e-3e89-4be5-9c1f-1b5e85950753" type="1">Inadequate Information Security Practices</Field>
            <Field id="31796" guid="24640c19-d1de-415b-b349-25b0af521373" type="6">2208289</Field>
            <Field id="41131" guid="7de0f37f-765a-4480-bbea-da1638ab3296" type="1">Cyber - 3</Field>
            <Field id="41132" guid="001a8562-9091-4e42-b96a-d17c33c19f6f" type="1">Define the Data Classification</Field>
        </Record>
    </Record>
    <Record contentId="2410661" levelId="463" levelGuid="cc59604e-cc41-4253-879a-5fbde3ffd760" moduleId="896" parentId="0">
        <Field id="41541" guid="bae76db7-4e46-4113-a453-68243a76d4f6" type="9">
            <Reference id="2208289">Inadequate Information Security Practices</Reference>
        </Field>
        <Field id="41485" guid="6fe04171-26b5-4bad-9430-d6d3d592c404" type="1">QL1 - LS Test - Architecture</Field>
    </Record>
    <Record contentId="2410666" levelId="463" levelGuid="cc59604e-cc41-4253-879a-5fbde3ffd760" moduleId="896" parentId="0">
        <Field id="41541" guid="bae76db7-4e46-4113-a453-68243a76d4f6" type="9">
            <Reference id="2208273"> Loss of 50% Staff </Reference>
        </Field>
        <Field id="41485" guid="6fe04171-26b5-4bad-9430-d6d3d592c404" type="1">QL3 - LS Test - Architecture</Field>
    </Record>
    <Record contentId="2410649" levelId="462" levelGuid="83a26d99-e79d-41af-8a20-fa069f791cef" moduleId="895" parentId="0">
        <Field id="41453" guid="9a764db7-a75e-4a49-9b26-de03e2bc4bb5" type="9">
            <Reference id="2208328">Technology Configuration</Reference>
        </Field>
        <Field id="41397" guid="c9574505-854b-44c2-aa4c-4a419c80b1e6" type="1">DG - Analytics</Field>
    </Record>
</Record>
</Records>

My expected output is :

<Record> 
        <uniqueValues>Unauthorized modification of Information/System - External</uniqueValues>
        <cyber>Cyber - 1</cyber>
        <question>Is all software that will be used for this initiative currently approved for use within</question>
    </Record>
    <Record>
        <uniqueValues>Inadequate Information Security Practices</uniqueValues>
        <cyber>Cyber - 10</cyber>
        <question>Will there be a requirement to connect a 3rd party to xxxxx network and what would be the purpose of this connection?</question>
    </Record>
    <Record> 
        <uniqueValues>Loss of Systems Including Data Center</uniqueValues>
        <cyber>Cyber - 11</cyber>
        <question>Is this product or service hosted or recovered </question>
    </Record>
    <Record>
         <uniqueValues>Loss of 50% Staff</uniqueValues>
        <question>QL3 - LS Test - Architecture</question> 
    </Record>
    <Record> 
        <uniqueValues>Technology Configuration</uniqueValues>
        <question>DG - Analytics</question>
    </Record>

I have tried using distinct values but it is giving me only atomic values i can't able to capture remining field values

<?xml version="1.0" encoding="utf-8"?>
  <xsl:stylesheet version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>
    
<xsl:output method="xml"/>
  <xsl:template match="Records">
    
       <xsl:for-each select="distinct-values((Record/Record/Field[@guid ='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'],Record/Record/Field[@guid ='bae76db7-4e46-4113-a453-68243a76d4f6']/Reference,Record/Record/Field[@guid ='9a764db7-a75e-4a49-9b26-de03e2bc4bb5']/Reference))">
             <Record>
                <uniqueValues><xsl:value-of select="."/></uniqueValues>
            </Record>
          </xsl:for-each> 
</xsl:template>
</xsl:stylesheet>

this gives only distinct values Could you please help me how can i write an xslt to get the expected output


Solution

  • Using

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        expand-text="yes"
        version="3.0">
      
      <xsl:mode on-no-match="shallow-skip"/>
    
      <xsl:output method="xml" indent="yes" />
    
      <xsl:template match="/Records">
        <xsl:copy>
          <xsl:for-each-group select="Record/Record" group-by="Record/Field[@guid ='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'], Field[@guid = ('bae76db7-4e46-4113-a453-68243a76d4f6', '9a764db7-a75e-4a49-9b26-de03e2bc4bb5')]/Reference">
            <xsl:copy>
              <uniqueValues>{current-grouping-key()}</uniqueValues>
              <xsl:apply-templates/>
            </xsl:copy>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="Field[@guid = '7de0f37f-765a-4480-bbea-da1638ab3296']">
        <cyber>
          <xsl:value-of select="."/>
        </cyber>
      </xsl:template>
      
     <xsl:template match="Field[@guid = ('001a8562-9091-4e42-b96a-d17c33c19f6f', '6fe04171-26b5-4bad-9430-d6d3d592c404', 'c9574505-854b-44c2-aa4c-4a419c80b1e6')]">
        <question>
          <xsl:value-of select="."/>
        </question>
      </xsl:template>
      
    </xsl:stylesheet>
    

    outputs

    <Records>
       <Record>
          <uniqueValues>Unauthorized modification of Information/System - External</uniqueValues>
          <cyber>Cyber - 1</cyber>
          <question>Is all software that will be used for this initiative currently approved for use within</question>
       </Record>
       <Record>
          <uniqueValues>Inadequate Information Security Practices</uniqueValues>
          <cyber>Cyber - 10</cyber>
          <question>Will there be a requirement to connect a 3rd party to xxxxx network and what would be the purpose of this connection?</question>
       </Record>
       <Record>
          <uniqueValues>Loss of Systems Including Data Center</uniqueValues>
          <cyber>Cyber - 11</cyber>
          <question>Is this product or service hosted or recovered </question>
       </Record>
       <Record>
          <uniqueValues> Loss of 50% Staff </uniqueValues>
          <question>QL3 - LS Test - Architecture</question>
       </Record>
       <Record>
          <uniqueValues>Technology Configuration</uniqueValues>
          <question>DG - Analytics</question>
       </Record>
    </Records>
    

    Of course the group-by expression with a sequence i.e. group-by="Record/Field[@guid ='2ebbfd8e-3e89-4be5-9c1f-1b5e85950753'], Field[@guid = ('bae76db7-4e46-4113-a453-68243a76d4f6', '9a764db7-a75e-4a49-9b26-de03e2bc4bb5')]/Reference" will only work if for each item in the grouping population only one of the subexpressions selects a key value and the other ones select the empty sequence.