1

I am trying to compare the text in a particular node (EN_PLAN_NAME) against a list of strings so I can output only nodes that contain text matching one of those strings. I tried using the answer from this similar question:

How to compare against multiple strings in xslt

INPUT XML

<EligibilityRecords xmlns="http://CDHC_Eligibility_LSDD">
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>Health Savings Account</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>zzHealth Reimbursement Arrangement</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>Health Reimbursement Arrangement 233</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>HRA</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>BASE HRA</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>FSA</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
</EligibilityRecords>

EXPECTED OUTPUT XML

<EligibilityRecords xmlns="CDHC_Eligibility_LSDD_Internal">
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>zzHealth Reimbursement Arrangement</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>Health Reimbursement Arrangement 233</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>HRA</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
  <Eligibility_Detail_Record xmlns="">
    <EN_PLAN_NAME>BASE HRA</EN_PLAN_NAME>
    <EN_MBRSHP_EFF_STRT_DT>01012017</EN_MBRSHP_EFF_STRT_DT>
  </Eligibility_Detail_Record>
</EligibilityRecords>

XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
                exclude-result-prefixes="msxsl var s0 ns0" version="1.0"
                xmlns:s0="CDHC_Eligibility_LSDD"
                xmlns:ns0="CDHC_Eligibility_LSDD_Internal">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />

  <xsl:param name="HRAPlanNames">
      <PlanName>Health Reimbursement Arrangement</PlanName>
      <PlanName>HRA</PlanName>
  </xsl:param>

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

  <xsl:template match="/*">
    <ns0:EligibilityRecords>
      <xsl:for-each select="Eligibility_Detail_Record">
        <xsl:if test="contains(EN_PLAN_NAME,msxsl:node-set($HRAPlanNames)/*)">
          <Eligibility_Detail_Record>
            <xsl:copy-of select="EN_PLAN_NAME"/>
          </Eligibility_Detail_Record>
        </xsl:if>
      </xsl:for-each>
    </ns0:EligibilityRecords>
  </xsl:template>
</xsl:stylesheet>

The XSLT outputs any EN_PLAN_NAME that has text containing "Health Reimbursement Arrangement" but does not output any node that contains "HRA". I'm not sure what I'm doing wrong.

Community
  • 1
  • 1
Ritley572
  • 299
  • 4
  • 15

2 Answers2

0

Note: You can take the translate() out of both examples. I had copied the input from your question before your edit.

I can't test msxsl right now, but try this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
  exclude-result-prefixes="msxsl var s0 ns0" version="1.0"
  xmlns:s0="CDHC_Eligibility_LSDD"
  xmlns:ns0="CDHC_Eligibility_LSDD_Internal">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />

  <xsl:param name="HRAPlanNames">
    <PlanName>HEALTH REIMBURSEMENT ARRANGEMENT</PlanName>
    <PlanName>HRA</PlanName>
  </xsl:param>

  <xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
  <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:for-each select="Eligibility_Detail_Record">
        <xsl:variable name="pn" select="translate(EN_PLAN_NAME,$lowercase,$uppercase)"/>
        <xsl:if test="msxsl:node-set($HRAPlanNames)/*[contains($pn,normalize-space())]">
          <Eligibility_Detail_Record>
            <xsl:copy-of select="EN_PLAN_NAME"/>
          </Eligibility_Detail_Record>
        </xsl:if>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

If that doesn't work, and you don't mind the plan names being hard coded in the XSLT (not using xsl:param), try something that doesn't use node-set():

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
  exclude-result-prefixes="msxsl var s0 ns0 local" version="1.0"
  xmlns:s0="CDHC_Eligibility_LSDD"
  xmlns:ns0="CDHC_Eligibility_LSDD_Internal"
  xmlns:local="local">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />

  <local:HRAPlanNames>
    <local:PlanName>HEALTH REIMBURSEMENT ARRANGEMENT</local:PlanName>
    <local:PlanName>HRA</local:PlanName>
  </local:HRAPlanNames>

  <xsl:variable name="planNames" 
    select="document('')/xsl:stylesheet/local:HRAPlanNames/local:PlanName"/>

  <xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
  <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:for-each select="Eligibility_Detail_Record">
        <xsl:variable name="pn" select="translate(EN_PLAN_NAME,$lowercase,$uppercase)"/>
        <xsl:if test="$planNames[contains($pn,normalize-space())]">
          <Eligibility_Detail_Record>
            <xsl:copy-of select="EN_PLAN_NAME"/>
          </Eligibility_Detail_Record>
        </xsl:if>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
0

The type of both arguments of the contains() function must be string. You are trying to use it with a node-set as the second argument, and (in XSLT 1.0) this will result in only the first node in the node-set being considered.

If you want to retain your current structure of the HRAPlanNames parameter, you will need to do something like:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="HRAPlanNames">
      <PlanName>Health Reimbursement Arrangement</PlanName>
      <PlanName>HRA</PlanName>
</xsl:param>

<xsl:template match="/*">
    <EligibilityRecords xmlns="CDHC_Eligibility_LSDD_Internal">
        <xsl:for-each select="Eligibility_Detail_Record">
            <xsl:variable name="plan-name" select="EN_PLAN_NAME" /> 
            <xsl:variable name="test">
                <xsl:for-each select="msxsl:node-set($HRAPlanNames)/PlanName">
                    <xsl:if test="contains($plan-name, .)">Y</xsl:if>
                </xsl:for-each>
            </xsl:variable>
            <xsl:if test="string($test)">
                <xsl:copy-of select="."/>
            </xsl:if>
        </xsl:for-each> 
    </EligibilityRecords>
</xsl:template>

</xsl:stylesheet>

in order to get the expected result.

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51