简体   繁体   中英

Create a concatenated, comma separated list from XML nodes at different levels in the XML tree using XPath/XSLT

I was asked to generate a comma separated list generated from an XML document. When the discounts only consisted of nodes grouped together under the vehicle node it worked OK (I have limited understanding of XPath). Then I was asked to add one more discount that is located in a different section of the XML. Using this approach I can't seem to get the value of the node I need. For clarification, I don't create this XML file, it is generated by a vendor system and is roughly 5K lines long. I used this post from SO as the basis for creating the list.


Desired Output (if node in loop != '0' or PaymentPlanCd != 'PaidInFull' add to the list - psuedo-code)

Multi-Car, Homeowner, Affinity, In-Agency Transfer, Advanced Purchase, Incident Free, Annual Mileage, Paid in Full Discount


I was getting an extra comma at the end so I changed to a whitespace based approach that seemed to work (Method 2). I would rather have the comma based approach (Method 1) though. Below is a sample of the XML document and the code I'm currently trying to make work. If there is an easier or more eloquent solution, I'm all ears.

Sample XML (@pval stands for "Proposal Value")

<dataStore>
  <session>
    <data>
        <policy>
            <PersPolicy>
                <PaymentOption>
                    <PaymentPlanCd>PaidInFull</PaymentPlanCd>
                </PaymentOption>
            </PersPolicy>
            <line>
                <vehicle id="1">
                    <DiscountPremMultiCar pval="Multi-Car">80</DiscountPremMultiCar>
                    <DiscountPremHomeowners pval="Homeowner">63</DiscountPremHomeowners>
                    <DiscountPremAffinity pval="Affinity">0</DiscountPremAffinity>
                    <DiscountPremInAgencyTransfer pval="In-Agency Transfer">57</DiscountPremInAgencyTransfer>
                    <DiscountPremAdvPurchase pval="Advanced Purchase">15</DiscountPremAdvPurchase>
                    <DiscountPremIncidentFree  pval="Incident Free">30</DiscountPremIncidentFree>
                    <DiscountPremAnnualMileage pval="Annual Mileage">0</DiscountPremAnnualMileage>
                </vehicle>                  
                <vehicle id="2">
                    <DiscountPremMultiCar pval="Multi-Car">80</DiscountPremMultiCar>
                    <DiscountPremHomeowners pval="Homeowner">63</DiscountPremHomeowners>
                    <DiscountPremAffinity pval="Affinity">0</DiscountPremAffinity>
                    <DiscountPremInAgencyTransfer pval="In-Agency Transfer">57</DiscountPremInAgencyTransfer>
                    <DiscountPremAdvPurchase pval="Advanced Purchase">15</DiscountPremAdvPurchase>
                    <DiscountPremIncidentFree  pval="Incident Free">30</DiscountPremIncidentFree>
                    <DiscountPremAnnualMileage pval="Annual Mileage">0</DiscountPremAnnualMileage>
                </vehicle>
            </line>
        </policy>
    </data>
  </session>
</dataStore>

XSLT/XPath

<xsl:for-each select="//session/data/policy/line/vehicle">
  <xsl:call-template name="VehicleDiscounts" />
</xsl:for-each>

Method 1

<xsl:template name="VehicleDiscounts">
  <xsl:for-each select="DiscountPremAdvPurchase/text() | DiscountPremAffinity/text() | DiscountPremAnnualMileage/text() | DiscountPremEmployee/text() | DiscountPremHomeowners/text() | DiscountPremInAgencyTransfer/text() | DiscountPremMultiCar/text() | DiscountPremMultiPolicy/text() | DiscountPremIncidentFree/text() | ../../../PersPolicy/PaymentOptions/PaymentPlanCd/text()">
    <xsl:if test="../. != '0'">
        <xsl:value-of select="../@pval"/>
        <xsl:if test="not(position() = last())">, </xsl:if>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

Method 2

<xsl:template name="VehicleDiscounts">
  <xsl:for-each select="DiscountPremAdvPurchase/text() | DiscountPremAffinity/text() | DiscountPremAnnualMileage/text() | DiscountPremEmployee/text() | DiscountPremHomeowners/text() | DiscountPremInAgencyTransfer/text() | DiscountPremMultiCar/text() | DiscountPremMultiPolicy/text() | DiscountPremIncidentFree/text() | ../../../PersPolicy/PaymentOptions/PaymentPlanCd/text()">
    <xsl:choose>
        <xsl:when test="name(../.) = 'DiscountPremAdvPurchase'">
          <xsl:if test="../. != '0'">
            Advance Purchase
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremAffinity'">
          <xsl:if test="../. != '0'">
            Affinity
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremEmployee'">
          <xsl:if test="../. != '0'">
            Group
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremHomeowners'">
          <xsl:if test="../. != '0'">
            Homeowners
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremInAgencyTransfer'">
          <xsl:if test="../. != '0'">
            In-Agency Transfer
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremMultiCar'">
          <xsl:if test="../. != '0'">
            Multi-Car
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremMultiPolicy'">
          <xsl:if test="../. != '0'">
            Multi-Policy
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremIncidentFree'">
          <xsl:if test="../. != '0'">
            Incident-Free
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
        <xsl:when test="name(../.) = 'DiscountPremAnnualMileage'">
          <xsl:if test="../. != '0'">
            Annual Mileage
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
<!-- This is what I have no clue about -->
        <xsl:when test="name(../.) = 'PaymentPlanCd'">
          Paid In Full Discount
          <xsl:if test="../. != '0'">
            Paid In Full Discount
            <xsl:if test="not(position() = last())">&#160;&#160;&#160;&#160;</xsl:if>
          </xsl:if>
        </xsl:when>
    </xsl:choose>
  </xsl:for-each>
</xsl:template>

How would I get method 1 working in this scenario? Thanks for all the help.

I am not sure what the difficulty here is. Could you try the following stylesheet and tell us - in simple, non-technical language - what (if anything) is missing?

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:template match="/">
    <xsl:text>Multi-Car,Homeowner,Affinity,In-Agency Transfer,Advanced Purchase,Incident Free,Annual Mileage,Paid in Full Discount&#10;</xsl:text>
    <xsl:for-each select="dataStore/session/data/policy/line/vehicle">
        <xsl:for-each select="*">
            <xsl:value-of select="."/>
            <xsl:text>,</xsl:text>
        </xsl:for-each>
        <xsl:value-of select="../../PersPolicy/PaymentOption/PaymentPlanCd"/>
        <xsl:if test="not(position()=last())">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM