Home > Mobile >  Looping the data in xslt 3.0 by streaming
Looping the data in xslt 3.0 by streaming

Time:11-05

I have a input file xml called offerings and I have the course xml both are in combined xml and the file should have all the titles that are in the course xml . In this case the number of titles present in offerings xml is 3 i.e

  • Launch Class Link - HDU_VILT01 - 1
  • Launch Class Link - HDU_VILT01 - 3
  • Launch Class Link - HDU_VILT01 - 5

but in Course xml there 6 Instructor_Led_Webinar_Lesson_Data titles So i need to loop in and show a validation that no matching lesson found. can anyone help in looping in Streaming mode.

Source xml

<?xml version='1.0' encoding='utf-8'?>
<FileAndCourses>
    <Maps>
        <Locations>
            <Location>
                <InternalValue>7070</InternalValue>
                <ExternalValue>Laval</ExternalValue>
            </Location>
            <Location>
                <InternalValue>7000</InternalValue>
                <ExternalValue>TORSSC</ExternalValue>
            </Location>
        </Locations>
            <Rooms>
                <Room>
                    <InternalValue>LOCATION-6-3881</InternalValue>
                    <ExternalValue>Ottawa District Training Center</ExternalValue>
                </Room>
            </Rooms>  
            
    </Maps>
    <Instructors>
        <Instructor>
        <InstructorID>119417764</InstructorID>
        <WorkdayUserName>AXH4006</WorkdayUserName>
    </Instructor>
    </Instructors>
      <AllCourses
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:wd="urn:com.workday/bsvc">
                <wd:Learning_Course>
            <wd:Learning_Blended_Course_Reference>
                <wd:ID wd:type="WID">88388986cbbf10128d2b24f4f5c40000</wd:ID>
                <wd:ID wd:type="Learning_Course_ID">00151744</wd:ID>
                <wd:ID wd:type="Learning_Course">Designing Kitchens Part II</wd:ID>
            </wd:Learning_Blended_Course_Reference>
            <wd:Learning_Course_Data>
                <wd:ID>00151744</wd:ID>
                <wd:Effective_Date>2014-10-04</wd:Effective_Date>
                <wd:Inactive>0</wd:Inactive>
                <wd:Course_Title>Designing Kitchens Part II</wd:Course_Title>
                <wd:Description>Designing Kitchens Part II</wd:Description>
                <wd:Course_Number>00151744</wd:Course_Number>
                <wd:Topic_Reference>
                    <wd:ID wd:type="WID">9d1f49654c8310154e239c7090fc0000</wd:ID>
                    <wd:ID wd:type="Learning_Topic">Product Knowledge - US</wd:ID>
                </wd:Topic_Reference>
                <wd:Language_Reference>
                    <wd:ID wd:type="WID">da594226446c11de98360015c5e6daf6</wd:ID>
                    <wd:ID wd:type="User_Language_ID">en_US</wd:ID>
                </wd:Language_Reference>
                <wd:Minimum_Enrollment_Capacity>0</wd:Minimum_Enrollment_Capacity>
                <wd:Maximum_Enrollment_Capacity>0</wd:Maximum_Enrollment_Capacity>
                <wd:Waitlist_Capacity>0</wd:Waitlist_Capacity>
                <wd:Unlimited_Capacity>1</wd:Unlimited_Capacity>
                <wd:Learning_Pricing_Data>
                    <wd:Pricing_Enabled>0</wd:Pricing_Enabled>
                    <wd:Price_in_Training_Credits>0</wd:Price_in_Training_Credits>
                </wd:Learning_Pricing_Data>
                <wd:Time_Value_Reference>
                    <wd:ID wd:type="WID">f31be4fd5caa10001d7c625e27014929</wd:ID>
                    <wd:ID wd:type="Learning_Time_Unit_ID">HOURS</wd:ID>
                </wd:Time_Value_Reference>
                <wd:Total_Course_Duration>18</wd:Total_Course_Duration>
                <wd:Enable_Auto_Enrollment_from_Waitlist>0</wd:Enable_Auto_Enrollment_from_Waitlist>
                <wd:Legacy_Course>1</wd:Legacy_Course>
                <wd:Allowed_Instructor_Reference>
                    <wd:ID wd:type="WID">88388986cbbf10124df56ab318140000</wd:ID>
                    <wd:ID wd:type="Learning_Instructor_ID">100735117</wd:ID>
                </wd:Allowed_Instructor_Reference>
                <wd:Allowed_Instructor_Reference>
                    <wd:ID wd:type="WID">b7f5fd27bc071018bbed7a460ce30000</wd:ID>
                    <wd:ID wd:type="Learning_Instructor_ID">119417764</wd:ID>
                </wd:Allowed_Instructor_Reference>
                <wd:Allowed_Instructor_Reference>
                    <wd:ID wd:type="WID">88388986cbbf10124df57b8e81f30002</wd:ID>
                    <wd:ID wd:type="Learning_Instructor_ID">104034590</wd:ID>
                </wd:Allowed_Instructor_Reference>
                <wd:All_Locations>0</wd:All_Locations>
                <wd:Exclude_from_Recommendations>1</wd:Exclude_from_Recommendations>
                <wd:Exclude_from_Search_and_Browse>0</wd:Exclude_from_Search_and_Browse>
                <wd:Disable_Express_Interest>1</wd:Disable_Express_Interest>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>1</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 1</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>2</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 2</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>3</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 3</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>4</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 4</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>5</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 5</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>6</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Instructor_Led_Webinar_Lesson_Data>
                        <wd:Title>Launch Class Link - HDU_VILT01 - 6</wd:Title>
                        <wd:Webinar_Lesson_Unit_Track_Attendance>1</wd:Webinar_Lesson_Unit_Track_Attendance>
                        <wd:Webinar_Lesson_Unit_Track_Grades>0</wd:Webinar_Lesson_Unit_Track_Grades>
                    </wd:Instructor_Led_Webinar_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>7</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>1</wd:Make_Lesson_Mandatory>
                    <wd:Media_Lesson_Data>
                        <wd:Media_Reference>
                            <wd:ID wd:type="WID">88388986cbbf10128d2b23247d3f0004</wd:ID>
                            <wd:ID wd:type="Media_ID">MEDIA-6-4195</wd:ID>
                            <wd:ID wd:type="Workdrive_Item_ID">MEDIA-6-4195</wd:ID>
                        </wd:Media_Reference>
                        <wd:Learning_Course_Lesson_Title>Welcome to HDU Distance Learning</wd:Learning_Course_Lesson_Title>
                        <wd:Provide_Course_Grade>0</wd:Provide_Course_Grade>
                    </wd:Media_Lesson_Data>
                </wd:Course_Lesson_Data>
                <wd:Course_Lesson_Data>
                    <wd:Lesson_Order>8</wd:Lesson_Order>
                    <wd:Make_Lesson_Mandatory>0</wd:Make_Lesson_Mandatory>
                    <wd:Media_Lesson_Data>
                        <wd:Media_Reference>
                            <wd:ID wd:type="WID">358e28e73d5d10109aef5b042fc20000</wd:ID>
                            <wd:ID wd:type="Media_ID">cninv000000000020562.zip</wd:ID>
                            <wd:ID wd:type="Workdrive_Item_ID">cninv000000000020562.zip</wd:ID>
                        </wd:Media_Reference>
                        <wd:Learning_Course_Lesson_Title>Course Feedback HDUv3</wd:Learning_Course_Lesson_Title>
                        <wd:Provide_Course_Grade>0</wd:Provide_Course_Grade>
                    </wd:Media_Lesson_Data>
                </wd:Course_Lesson_Data>
            </wd:Learning_Course_Data>
        </wd:Learning_Course>
                    </AllCourses>
       <Offerings>
        <Offering>
            <Lesson>
                <Offering-ID>C2212001 DL 3Wks Mon 4pm-7pm EASTERN</Offering-ID>
                <Course-Number>00151744</Course-Number>
                <Min-Seats>10</Min-Seats>
                <Max-Seats>20</Max-Seats>
                <Webinar>Y</Webinar>
                <Title>Launch Class Link - HDU_VILT01 - 1</Title>
                <Start-Date>11/28/2022</Start-Date>
                <Start-Time>04:00PM</Start-Time>
                <End-Date>11/28/2022</End-Date>
                <End-Time>07:00PM</End-Time>
                <Facilitator-LDAP>AXH4006</Facilitator-LDAP>
                <Location/>
                <Room/>
                <Language>en_US</Language>
                <Webinar-URL>https://hdu.adobeconnect.com</Webinar-URL>
            </Lesson>
            <Lesson>
                <Offering-ID>C2212001 DL 3Wks Mon 4pm-7pm EASTERN</Offering-ID>
                <Course-Number>00151744</Course-Number>
                <Min-Seats>10</Min-Seats>
                <Max-Seats>20</Max-Seats>
                <Webinar>Y</Webinar>
                <Title>Launch Class Link - HDU_VILT01 - 3</Title>
                <Start-Date>12/05/2022</Start-Date>
                <Start-Time>04:00PM</Start-Time>
                <End-Date>12/05/2022</End-Date>
                <End-Time>07:00PM</End-Time>
                <Facilitator-LDAP>AXH4006</Facilitator-LDAP>
                <Location/>
                <Room/>
                <Language>en_US</Language>
                <Webinar-URL>https://hdu.adobeconnect.com</Webinar-URL>
            </Lesson>
            <Lesson>
                <Offering-ID>C2212001 DL 3Wks Mon 4pm-7pm EASTERN</Offering-ID>
                <Course-Number>00151744</Course-Number>
                <Min-Seats>10</Min-Seats>
                <Max-Seats>20</Max-Seats>
                <Webinar>Y</Webinar>
                <Title>Launch Class Link - HDU_VILT01 - 5</Title>
                <Start-Date>12/12/2022</Start-Date>
                <Start-Time>04:00PM</Start-Time>
                <End-Date>12/12/2022</End-Date>
                <End-Time>07:00PM</End-Time>
                <Facilitator-LDAP>AXH4006</Facilitator-LDAP>
                <Location/>
                <Room/>
                <Language>en_US</Language>
                <Webinar-URL>https://hdu.adobeconnect.com</Webinar-URL>
            </Lesson>
        </Offering>
            </Offerings>
</FileAndCourses>

I used streaming using xslt 3.0. I need to loop and put the validation. All the titles in inputfile should match the Course titles else a validation should be displayed.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="xs" version="3.0"
    xmlns:wd="urn:com.workday/bsvc" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <xsl:output method="xml" indent="yes"/>
    <xsl:mode streamable="yes" on-no-match="shallow-skip"/>  
    
    
    <xsl:template match="/FileAndCourses">
        <OfferingsWithCourse>
            <xsl:iterate select="*">
               
                <xsl:param name="LearningCoursesMap" as="map(xs:string,element(wd:Learning_Course))" select="map{}"/>
                
                <xsl:choose>
                    
                    <xsl:when test="self::AllCourses">
                        <xsl:next-iteration>
                            <xsl:with-param name="LearningCoursesMap"
                                select="fold-left(
                                wd:Learning_Course/copy-of(),
                                map{},
                                function($map,$entry) {
                                let $key:=xs:string($entry/wd:Learning_Course_Data/wd:ID) return
                                if ($key)
                                then map:put($map,$key,$entry)
                                else
                                $map})"
                            />
                        </xsl:next-iteration>
                    </xsl:when>
                        <xsl:when test="self::Offerings">
                        <xsl:for-each select="Offering/copy-of()">
                            <Offering>
                                <xsl:for-each select="Lesson/copy-of()">
                                    <Lesson>
                                        <xsl:copy-of select="./*"/>
                                                                                
                                        <xsl:choose>
                                            <xsl:when test="exists($LearningCoursesMap(current()/Course-Number))">
                                                <xsl:if test="Title != '' and Webinar = 'N' and not(exists($LearningCoursesMap(current()/Course-Number)[wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Lesson_Data/wd:Title = current()/Title]))">
                                                    <Error>
                                                        <xsl:text>No intructor-led classrom lesson found in course with title: </xsl:text>
                                                        <xsl:value-of select="Title"/>
                                                        <xsl:text>. </xsl:text>
                                                    </Error>
                                                </xsl:if> 
                                                <xsl:if test="Title != '' and Webinar = 'Y' and not(exists($LearningCoursesMap(current()/Course-Number)[wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Webinar_Lesson_Data/wd:Title = current()/Title]))">
                                                    <Error>
                                                        <xsl:text>No intructor-led webinar lesson found in course with title: </xsl:text>
                                                        <xsl:value-of select="Title"/>
                                                        <xsl:text>. </xsl:text>
                                                    </Error>
                                                </xsl:if> 
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <Error>
                                                    <xsl:text>Unable to find active course </xsl:text>
                                                    <xsl:value-of select="Course-Number"/>
                                                    <xsl:text> in Workday. </xsl:text>
                                                </Error>
                                            </xsl:otherwise>
                                        </xsl:choose>                                        
                                      
                                    </Lesson>
                                </xsl:for-each>    
                                
                            </Offering>
                        </xsl:for-each>
                    </xsl:when>
                </xsl:choose>
            </xsl:iterate>
        </OfferingsWithCourse>
    </xsl:template>
</xsl:stylesheet>

CodePudding user response:

The simplest way of doing this might be to use streaming to delete all the data that isn't relevant to the problem, and then use a non-streaming conventional stylesheet to test the join conditions.

CodePudding user response:

If the task is to find for any Offerings/Offering/Lesson/Title a matching wd:LearningCourse based on the Course-Number/wd:ID and then to compare Title and wd:Course_Lesson_Data's wd:Title then here is an approach using streaming:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:wd="urn:com.workday/bsvc"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:accumulator name="learning-course-id" as="xs:string?" initial-value="()" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:ID/text()" select="string()"/>
  </xsl:accumulator>
  
  <xsl:accumulator name="webinars" as="map(xs:string, xs:string*)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Webinar_Lesson_Data/wd:Title/text()" 
      select="let $id := accumulator-before('learning-course-id')
              return
                if (map:contains($value, $id))
                then map:put($value, $id, ($value($id), string()))
                else map:put($value, $id, string())"/>
  </xsl:accumulator>
  
  <xsl:accumulator name="classroom-lessons" as="map(xs:string, xs:string*)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Lesson_Data/wd:Title/text()" 
      select="let $id := accumulator-before('learning-course-id')
              return
                if (map:contains($value, $id))
                then map:put($value, $id, ($value($id), string()))
                else map:put($value, $id, string())"/>
  </xsl:accumulator>

  <xsl:mode on-no-match="shallow-skip" use-accumulators="#all" streamable="yes"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/FileAndCourses">
    <OfferingsWithCourse>
      <xsl:apply-templates select="Offerings/Offering"/>
    </OfferingsWithCourse>
  </xsl:template>
  
  <xsl:template match="Offering/Lesson">
    <xsl:apply-templates select="copy-of()" mode="grounded"/>
  </xsl:template>
  
  <xsl:mode name="grounded" on-no-match="shallow-copy"/>
  
  <xsl:template mode="grounded" match="Lesson[Webinar = 'Y'][let $webinars := accumulator-before('webinars') return if (map:contains($webinars, Course-Number)) then not(Title = $webinars(Course-Number)) else false()]">
    <xsl:copy>
      <xsl:copy-of select="*"/>
      <Error>
          <xsl:text>No intructor-led webinar lesson found in course with title: </xsl:text>
          <xsl:value-of select="Title"/>
          <xsl:text>. </xsl:text>
      </Error>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template mode="grounded" match="Lesson[Webinar = 'N'][let $lessons := accumulator-before('classroom-lessons') return if (map:contains($lessons, Course-Number)) then not(Title = $lessons(Course-Number)) else false()]">
    <xsl:copy>
      <xsl:copy-of select="*"/>
        <Error>
            <xsl:text>No intructor-led classrom lesson found in course with title: </xsl:text>
            <xsl:value-of select="Title"/>
            <xsl:text>. </xsl:text>
        </Error>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template mode="grounded" match="Lesson[Webinar = 'Y'][not(map:contains(accumulator-before('webinars'), Course-Number))] | Lesson[Webinar = 'N'][not(map:contains(accumulator-before('classroom-lessons'), Course-Number))]">
    <xsl:copy>
      <xsl:copy-of select="*"/>
        <Error>
            <xsl:text>Unable to find active course </xsl:text>
            <xsl:value-of select="Course-Number"/>
            <xsl:text> in Workday. </xsl:text>
        </Error>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

The other way around, to check whether there are offerings for given wd:Course_Lesson_Data would be

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:wd="urn:com.workday/bsvc"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:accumulator name="learning-course-id" as="xs:string?" initial-value="()" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:ID/text()" select="string()"/>
  </xsl:accumulator>

  <xsl:accumulator name="lesson-mandatory" as="xs:boolean?" initial-value="()" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data" select="false()"/>
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Make_Lesson_Mandatory/text()" select=". = 1"/>
  </xsl:accumulator>
  
  <xsl:accumulator name="webinars" as="map(xs:string, xs:string*)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Webinar_Lesson_Data[accumulator-before('lesson-mandatory')]/wd:Title/text()" 
      select="let $id := accumulator-before('learning-course-id')
              return
                if (map:contains($value, $id))
                then map:put($value, $id, ($value($id), string()))
                else map:put($value, $id, string())"/>
  </xsl:accumulator>
  
  <xsl:accumulator name="classroom-lessons" as="map(xs:string, xs:string*)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="AllCourses/wd:Learning_Course/wd:Learning_Course_Data/wd:Course_Lesson_Data/wd:Instructor_Led_Lesson_Data[accumulator-before('lesson-mandatory')]/wd:Title/text()" 
      select="let $id := accumulator-before('learning-course-id')
              return
                if (map:contains($value, $id))
                then map:put($value, $id, ($value($id), string()))
                else map:put($value, $id, string())"/>
  </xsl:accumulator>

  <xsl:accumulator name="offered-lesson-id" as="xs:string?" initial-value="()" streamable="yes">
    <xsl:accumulator-rule match="Offerings/Offering/Lesson/Course-Number/text()" select="string()"/>
  </xsl:accumulator>

  <xsl:accumulator name="offered-lessons" as="map(xs:string, xs:string*)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule match="Offerings/Offering/Lesson/Title/text()" 
      select="let $id := accumulator-before('offered-lesson-id')
              return
                if (map:contains($value, $id))
                then map:put($value, $id, ($value($id), string()))
                else map:put($value, $id, string())"/>
  </xsl:accumulator>

  <xsl:mode on-no-match="shallow-skip" use-accumulators="#all" streamable="yes"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/FileAndCourses" expand-text="yes">
    <OfferingsWithCourse>
      <xsl:apply-templates/>
      <xsl:variable name="webinars" select="accumulator-after('webinars')"/>
      <xsl:variable name="offered-lessons" select="accumulator-after('offered-lessons')"/>
      <xsl:for-each select="map:keys(accumulator-after('webinars'))">
        <xsl:variable name="webinar-id" select="."/>
        <xsl:for-each select="$webinars(.)[not(. = $offered-lessons($webinar-id))]">
          <Error>No offering for {$webinar-id} title {.}</Error>
        </xsl:for-each>
      </xsl:for-each>
    </OfferingsWithCourse>
  </xsl:template>
  
</xsl:stylesheet>

For your sample data, this outputs

<?xml version="1.0" encoding="UTF-8"?>
<OfferingsWithCourse>
   <Error>No offering for 00151744 title Launch Class Link - HDU_VILT01 - 2</Error>
   <Error>No offering for 00151744 title Launch Class Link - HDU_VILT01 - 4</Error>
   <Error>No offering for 00151744 title Launch Class Link - HDU_VILT01 - 6</Error>
</OfferingsWithCourse>
  • Related