Template match prints everything from matching tag

2019-08-20 06:53发布

Why does it print everything from tag when I do ? I just want to get into that node so I don't have to type always the path? Here is example XML:

           <?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="blablabla" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <CstmrCdtTrfInitn>
      <GrpHdr>
         <MsgId>35006</MsgId>
         <CreDtTm>2017-04-13T08:30:09</CreDtTm>
         <NbOfTxs>3</NbOfTxs>
         <CtrlSum>22000.00</CtrlSum>
         <InitgPty>
            <Nm>XXXXX</Nm>
            <Id>
               <OrgId>
                  <Othr>
                     <Id>0000010681</Id>
                  </Othr>
               </OrgId>
            </Id>
         </InitgPty>
      </GrpHdr>
      <PmtInf>
         <PmtInfId>35006_26011</PmtInfId>
         <PmtMtd>TRF</PmtMtd>
         <NbOfTxs>3</NbOfTxs>
         <CtrlSum>22000.00</CtrlSum>
         <PmtTpInf />
         <ReqdExctnDt>2017-04-13</ReqdExctnDt>
         <Dbtr>
            <Nm>WWWWWWW</Nm>
            <PstlAdr>
               <StrtNm>AAAAAA</StrtNm>
               <PstCd>BBBBBB</PstCd>
               <TwnNm>CCCCCC</TwnNm>
               <Ctry>PL</Ctry>
            </PstlAdr>
            <Id>
               <OrgId>
                  <Othr>
                     <Id>0000010681</Id>
                  </Othr>
               </OrgId>
            </Id>
         </Dbtr>
      </PmtInf>
   </CstmrCdtTrfInitn>
</Document>

Here is what I want to receive:

1.  XXXXX
2.  AAAAAA
3.  BBBBBB
4.  CCCCCC

And I'm getting:

350062017-04-13T08:30:09322000.00XXXXX0000010681
  1.
  WWWWWWW
  2.
  AAAAAA
  3.
  BBBBBB
  4.
  CCCCCC

Using this XLST:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="blablabla" version="1.0">
   <xsl:output method="text" encoding="utf-8" />
   <xsl:strip-space elements="*" />
   <xsl:template match="doc:PmtInf">
      1.
      <xsl:value-of select="doc:Dbtr/doc:Nm" />
      2.
      <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:StrtNm" />
      3.
      <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:PstCd" />
      4.
      <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:TwnNm" />
   </xsl:template>
</xsl:stylesheet>

标签: xml xslt
2条回答
啃猪蹄的小仙女
2楼-- · 2019-08-20 07:38

This is because of built-in template rules which are used when the processor cannot find a matching template in your XSLT

Processing of the XML starts by XSLT looking for a template that matches the document node (represented by a /) and because you don't have a template matching in your XSLT the built-in template applies

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

This will simply pass over the node, and look for templates matching child nodes.

When it gets to CstmrCdtTrfInitn, you also don't have a matching template, so the built-in template still applies to select its children. You do have a template matching pmtInf but not GrpHdr. For the GrpHdr element, eventually the built-in template will reach text nodes, which gets matched by these

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

In other words, the built-in templates outputs any text nodes it finds, which is why you get the extra text.

What you could do, is add a template that matches GrpHdr and tells XSLT to go no further

<xsl:template match="doc:GrpHdr" />

Or you could have a template that matches doc:CstmrCdtTrfInitn that then selects only the child node you want.

<xsl:template match="doc:CstmrCdtTrfInitn">
  <xsl:apply-templates select="doc:PmtInf" />
</xsl:template>

If you did not want to rely on built-in templates at all, or if you have other elements in your XML that are coming into play where you don't want them, you could also try adding this template instead, to match the document node, and then jump straigt to the PmtInf node.

 <xsl:template match="/">
    <xsl:apply-templates select="doc:Document/doc:CstmrCdtTrfInitn/doc:PmtInf" />
 </xsl:template>

As an example, this should give you the result you need

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="blablabla" version="1.0">
   <xsl:output method="text" encoding="utf-8" />
   <xsl:strip-space elements="*" />

   <xsl:template match="doc:GrpHdr" />

   <xsl:template match="doc:PmtInf">
      1. <xsl:value-of select="doc:Dbtr/doc:Nm" />
      2. <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:StrtNm" />
      3. <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:PstCd" />
      4. <xsl:value-of select="doc:Dbtr/doc:PstlAdr/doc:TwnNm" />
   </xsl:template>
</xsl:stylesheet>
查看更多
相关推荐>>
3楼-- · 2019-08-20 07:40

change

      <xsl:value-of select="doc:Dbtr/doc:Nm" />

To

      <xsl:value-of select="ancestor-or-self::Document/CstmrCdtTrfInitn/GrpHdr/InitgPty/Nm" />

ancestor-or-self gives you the possebility to select from the top node of your xml document

查看更多
登录 后发表回答