XSLT selecting mulitple nodes with different names

2019-09-01 05:38发布

I am relatively new to XSLT, and I am having trouble coming up with a logic to select attributes and node values from a given xml.

Here is the xml I have,

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:head="http://www/example.com">
  <soap:Header>
      <head:sampleHeaderType>
        <head:messageId>xxxxxxxx</head:messageId>
         <head:SID>XXX</head:SID>
         <head:BID>SP</head:BID>
         <head:CTS>2014-09-26T13:19:30.534Z</head:CTS>      
      </head:sampleHeaderType>
   </soap:Header>
   <soap:Body>
      <cass:SPD xmlns:cass="http://blahblahblah">
         <cass:SPR>
            <cass:RQ RT="Describe" FG="LOL" PD="09/22/2014" />
         </cass:SPR>
         <cass:SPS>
            <cass:SP SPT="Standard" FT="Retail" PS="New" ICT="APR" >
               <cass:DR DN="306532" BR="0.0790000">
                  <cass:FFMR ValueType="$" Value="0"/>
                  <cass:RV ReserveType="DP">
                     <cass:RTS TT="DP">
                        <cass:RT TMin="0" TMax="0.999999" TVT="%" TV="100"/>
                     </cass:RTS>
                  </cass:RV>
               </cass:DR>
               <cass:Product PID="Sirius" PN="Sirius"/>
            </cass:SP>
            <cass:SP SPT="Standard" FT="Retail" PS="New" ICT="APR">
               <cass:DR DN="306532" BR="0.1520000">
                  <cass:FFMR ValueType="$" Value="0"/>
                  <cass:RV RT="DP">
                     <cass:RTS TT="DP">
                        <cass:RT TMin="0" TMax="0.999999" TVT="%" TV="100"/>
                     </cass:RTS>
                  </cass:RV>
               </cass:DR>
               <cass:Product PID="Sirius" PN="Sirius"/>
            </cass:SP>
         </cass:SPS>
         <cass:SPMS>
            <cass:SPM MessageCode="" MessageType="" MessageText=""/>
         </cass:SPMS>
</cass:SPD>
   </soap:Body>
</soap:Envelope>

And here is the output I am expecting:

<CALL_ENGINE_RESPONSE>
<EVAPP_SP>
<RT>Describe</RT>
<FG>LOL</FG>
<ICT>APR</ACT>
<DN>306532</DN>
<TMIN>0</TMIN>
<MessageCode></MessageCode>
<MessageText></MessageText>
</EVAPP_SP>
<EVAPP_SP>
<RT>Describe</RT>
<FG>LOL</FG>
<ICT>APR</ACT>
<DN>306532</DN>
<TMIN>0</TMIN>
<MessageCode></MessageCode>
<MessageText></MessageText>
</EVAPP_SP>
</CALL_ENGINE_RESPONSE>

So basically, there can be multiples SPS segments in the xml, and for each SPS, we want to construct a seperate XML with the EVAPP_SP tag. However RQ and SPM come only once.

My stylesheet may look horrible, because of my ignorance, but here it is :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:cass="http://blahblahblah" xmlns:head="http://www/example.com" exclude-result-prefixes="soap cass head">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="cass:SPD">
        <CALL_ENGINE_RESPONSE>
        <xsl:apply-templates select="cass:SPM"/>
        <xsl:apply-templates select="cass:RQ"/>
        <xsl:apply-templates select="cass:SP"/>
        </CALL_ENGINE_RESPONSE>
   </xsl:template>

   <xsl:template match="cass:RQ">
      <EVAPP_SP>
      <RT>
         <xsl:value-of select="@RT"/>
      </RT>
      <FG>
         <xsl:value-of select="@FG"/>
      </FG>
      <PD>
         <xsl:value-of select="@PD"/>
      </PD>
      </EVAPP_SP>
    </xsl:template>

    <xsl:template match="cass:SPM">
        <EVAPP_SP>
        <MESSAGE_TXT>
            <xsl:value-of select="@MessageText"/>
        </MESSAGE_TXT>
        </EVAPP_SP>
    </xsl:template>
</xsl:stylesheet>

So far, I get the output :

    xxxxxxxx
     XXX
     SP
     2014-09-26T13:19:30.534Z



  <CALL_ENGINE_RESPONSE/>

It is picking up the header information, a namespace and tag that I want to completely ignore.

Can someone please suggest a good direction in which I have to head? For example, how do I make my stylesheet ignore the header?

标签: xml xslt soap
1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-09-01 06:15

The behaviour you are seeing with the header is due to XSLT's built-in template rules. These are templates that are used when XSLT is looking for a template match but there is no matching one in your XSLT.

You have a template matching "cass:SPD". However, the elements "soap:Header" and "soap:Body" come before this, so the default template will be used for these. Ultimately, the built-in templates will output text nodes, which is why you see the header text appearing.

To stop this, just add this template match to your XSLT

<xsl:template match="soap:Header" />

The other issue I can see is that in your template matching "cass:SPD" you do this

<xsl:apply-templates select="cass:SPM"/>
<xsl:apply-templates select="cass:RQ"/>
<xsl:apply-templates select="cass:SP"/>

But none of these elements appear to be child nodes of "cass:SPD", so you probably need to do this:

<xsl:apply-templates select="*/cass:SPM"/>
<xsl:apply-templates select="*/cass:RQ"/>
<xsl:apply-templates select="*/cass:SP"/>

Or maybe this, if you don't know how far down they occur

<xsl:apply-templates select=".//cass:SPM"/>
<xsl:apply-templates select=".//cass:RQ"/>
<xsl:apply-templates select=".//cass:SP"/>
查看更多
登录 后发表回答