xmlxslttransformationancestor

Need help in generating text output from XML file


Need help with building an XSL version 2.0 file in converting XML file to text output.

Below is the XML file. For all the elements that have field as "Checked = 'Y'" we need a "[X]" concatenated before the text output.

Tab spaces should be based on the level of ansestor-tags.

<Review>
	<Assignment/>
	<Authorization/>
	<Criteria>
		<Components/>
		<OrganizationalPolicy/>
		<DecisionPoints/>
		<Notes/>
		<QualityIndicators/>
		<Responses>
			<Response CPID="AISD01590403010101" Checked="Y"/>
			<Response CPID="AISD01590403010102" Checked="Y"/>
			<Response CPID="AISD01590403010103" Checked="Y"/>
			<Response CPID="AISD0159040301010401" Checked="Y"/>
			<Response CPID="AISD01590403010104" Met="Y"/>
			<Response CPID="AISD015904030101" Met="Y"/>
			<Response CPID="AISD0159040301010402" Checked="Y"/>
			<Response CPID="AISD0159040301010403" Checked="Y"/>
			<Response CPID="AISD0159040301010404" Met="Y"/>
			<Response CPID="AISD015904030101040401" Checked="Y"/>
			<Response CPID="AISD015904030101040402" Checked="Y"/>
			<Response CPID="AISD015904030101040403" Checked="Y"/>
			<Response CPID="AISD015904030101040404" Checked="Y"/>
			<Response CPID="AISD0159040301010405" Checked="Y"/>
		</Responses>
		<QuestionsAsked/>
	</Criteria>
	<ReviewSummaryXML>
		<CP ID="AISD015901" Txt="(Symptom or finding within 24h)"/>
		<CP ID="AISD015902" Txt="(Excludes PO medications unless noted)">
			<CP ID="AISD015904" Txt="Select Day, One:">
				<CP ID="AISD01590401" Txt="Pre-op Day, One:"/>
				<CP ID="AISD01590402" Txt="Operative Day, One:"/>
				<CP ID="AISD01590403" Txt="Post-op Day 1, One:">
					<CP ID="AISD0159040301" Txt="OBSERVATION, One:">
						<CP Checked="Y" ID="AISD015904030101" Txt="Responder, discharge expected today if clinically stable last 12h, All:">
							<CP Checked="Y" ID="AISD01590403010101" Txt="Able to perform ADLs or return to baseline"/>
							<CP Checked="Y" ID="AISD01590403010102" Txt="Pain controlled or manageable"/>
							<CP Checked="Y" ID="AISD01590403010103" Txt="Tolerating PO or nutritional route established"/>
							<CP Checked="Y" ID="AISD01590403010104" Txt="Complication or comorbidity, &gt;= One:">
								<CP Checked="Y" ID="AISD0159040301010401" Txt="No complication or active comorbidity relevant to this episode of care"/>
								<CP Checked="Y" ID="AISD0159040301010402" Txt="Arrhythmia controlled"/>
								<CP Checked="Y" ID="AISD0159040301010403" Txt="Bleeding controlled or manageable"/>
								<CP Checked="Y" ID="AISD0159040301010404" Txt="Recovered from anesthesia, All:">
									<CP Checked="Y" ID="AISD015904030101040401" Txt="Stable level of consciousness"/>
									<CP Checked="Y" ID="AISD015904030101040402" Txt="Mobility and coordination at baseline"/>
									<CP Checked="Y" ID="AISD015904030101040403" Txt="Sensation intact"/>
									<CP Checked="Y" ID="AISD015904030101040404" Txt="O2 sat &gt;= 92%(0.92) or within acceptable limits"/>
								</CP>
								<CP Checked="Y" ID="AISD0159040301010405" Txt="Passing urine without urinary retention"/>
								<CP ID="AISD0159040301010406" Txt="Postoperative vomiting resolved"/>
							</CP>
						</CP>
					</CP>
				</CP>
				<CP ID="AISD01590404" Txt="Post-op Day 2, One:"/>
				<CP ID="AISD01590405" Txt="Post-op Day 3, One:"/>
				<CP ID="AISD01590406" Txt="Post-op Day 4, One:"/>
				<CP ID="AISD01590407" Txt="Post-op Day 5, One:"/>
				<CP ID="AISD01590408" Txt="Post-op Day 6-10, One:"/>
				<CP ID="AISD01590409" Txt="Post-op Day 11, One:"/>
			</CP>
		</CP>
	</ReviewSummaryXML>
</Review>

Expected output is as given below.

(Excludes PO medications unless noted)
	Select Day, One:
		Post-op Day 1, One
			OBSERVATION, One:
				[X] Responder, discharge expected today if clinically stable last 12h, All:
					[X] Able to perform ADLs or return to baseline
					[X] Pain controlled or manageable
					[X]	Tolerating PO or nutritional route established
					[X] Complication or comorbidity, &gt;= One:
						[X]	No complication or active comorbidity relevant to this episode of care
						[X]	Arrhythmia controlled
						[X] Bleeding controlled or manageable
						[X] Recovered from anesthesia, All:
							[X]	Stable level of consciousness
							[X] Mobility and coordination at baseline
							[X] Sensation intact
							[X] O2 sat &gt;= 92%(0.92) or within acceptable limits
								[X] Passing urine without urinary retention


Solution

  • In your XSLT, you seem to be only selecting elements where Checked is "Y"

    <xsl:for-each select="descendant-or-self::*[@Checked='Y']">
    

    So, all other elements are ignored. I think you should be selecting elements with a Txt attribute here:

     <xsl:for-each select="descendant-or-self::*[@Txt]">
    

    (And similarly for the count)

    Then, to determine whether to show an "[X]" at the front, you can do this:

    <xsl:if test="@Checked='Y'">[X] </xsl:if>
    <xsl:value-of select="@Txt"/>
    

    Or maybe this:

    <xsl:value-of select="concat(if (@Checked = 'Y') then '[X] ' else '', @Txt)"/>
    

    Try this XSLT

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes" method="text"/>
    
        <xsl:strip-space elements="*" />
    
        <xsl:template match="ReviewSummaryXML">
            <xsl:for-each select="descendant-or-self::*[@Txt]">
                <xsl:call-template name="tab">
                    <xsl:with-param name="ancestor-count" select="count(ancestor::*[@Txt])"/>
                </xsl:call-template>
                <xsl:value-of select="concat(if (@Checked = 'Y') then '[X] ' else '', @Txt)"/><xsl:text>&#x0a;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template name="tab">
            <xsl:param name="ancestor-count"/>
            <xsl:for-each select="1 to $ancestor-count">
                <xsl:text>&#x9;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>
    

    Note the use of xsl:strip-space too, to avoid excess whitespace being output before your text.

    EDIT - In answer to your comment, if you only want to output elements where @Checked is "Y" or they have a descendant that has @Checked equal to "Y", add the condition [descendant-or-self::*/@Checked='Y'] to the relevant expressions.

    Try this XSLT:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes" method="text"/>
    
        <xsl:strip-space elements="*" />
    
        <xsl:template match="ReviewSummaryXML">
            <xsl:for-each select="descendant-or-self::*[@Txt][descendant-or-self::*/@Checked='Y']">
                <xsl:call-template name="tab">
                    <xsl:with-param name="ancestor-count" select="count(ancestor::*[@Txt][descendant-or-self::*/@Checked='Y'])"/>
                </xsl:call-template>
                <xsl:value-of select="concat(if (@Checked = 'Y') then '[X] ' else '', @Txt)"/><xsl:text>&#x0a;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template name="tab">
            <xsl:param name="ancestor-count"/>
            <xsl:for-each select="1 to $ancestor-count">
                <xsl:text>&#x9;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>
    

    EDIT 2: If you want an XSLT 1.0 solution, try this....

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="1.0">
    
        <xsl:output indent="yes" method="text"/>
    
        <xsl:strip-space elements="*" />
    
        <xsl:template match="ReviewSummaryXML">
            <xsl:for-each select="descendant-or-self::*[@Txt][descendant-or-self::*/@Checked='Y']">
                <xsl:call-template name="tab">
                    <xsl:with-param name="ancestors" select="ancestor::*[@Txt][descendant-or-self::*/@Checked='Y']"/>
                </xsl:call-template>
                <xsl:if test="@Checked = 'Y'">[X] </xsl:if>
                <xsl:value-of select="@Txt"/>
                <xsl:text>&#x0a;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template name="tab">
            <xsl:param name="ancestors"/>
            <xsl:for-each select="$ancestors">
                <xsl:text>&#x9;</xsl:text>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>