Home > other >  How to select only top level tags?
How to select only top level tags?

Time:05-14

I`ve a xml file:

<response>
<ERROR_CODE>0</ERROR_CODE>
<result>
    <value>
        <Account>L01 00000F00</Account>
        <SecurCode>RU000A1017H9</SecurCode>
        <Accruedint>0.0000</Accruedint>
        <ComisClear>0.0000</ComisClear>
    </value>
    <value>
        <Account>1231 00000F00</Account>
        <SecurCode>RU000A1017H9</SecurCode>
        <Accruedint>0.12300</Accruedint>
        <ComisClear>0.012300</ComisClear>
    </value>
</result>

I wanna wrap all values deep value tag on <![CDATA]]> tag. Now i try to do that way:

<xsl:template match="/">
    <response>
        <xsl:apply-templates select="response"/>
    </response>
</xsl:template>

<xsl:template match="response">
    <xsl:for-each select="*">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="substring(*,1,3)"/>
            <xsl:value-of select="current()"/>
        </xsl:element>
    </xsl:for-each>
    <xsl:apply-templates select="value"/>
</xsl:template>

<xsl:template match="value">
    <xsl:element name="value">
       <xsl:apply-templates select="*"/>
    </xsl:element>
</xsl:template>

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:value-of select="substring(*,1,3)"/>
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
        <xsl:value-of select="current()"/>
        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:element>
</xsl:template>

Excepted XML:

<response>
<ERROR_CODE>0</ERROR_CODE>
<result>
    <value>
        <Account><![CDATA[L01 00000F00]]></Account>
        <SecurCode><![CDATA[RU000A1017H9]]></SecurCode>
        <Accruedint><![CDATA[0.0000]]></Accruedint>
        <ComisClear><![CDATA[0.0000]]></ComisClear>
    </value>
    <value>
        <Account><![CDATA[1231 00000F00]]></Account>
        <SecurCode><![CDATA[RU000A1017H9]]></SecurCode>
        <Accruedint><![CDATA[0.12300]]></Accruedint>
        <ComisClear><![CDATA[0.012300]]></ComisClear>
    </value>

Data in value tag always diferent (i`m generating custom fileds every time)

But i have a problem on <xsl:for-each select="*"> becouse it`s including ALL nodes, so how i can just foreach on top level tags??

CodePudding user response:

Please try the following solution.

It is using a so called Identity Transform pattern, and the cdata-section-elements attribute to enlist all desired elements for a CData section.

XSLT

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" encoding="utf-8" indent="yes" cdata-section-elements="Account SecurCode Accruedint ComisClear"/>
   <xsl:strip-space elements="*"/>

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

CodePudding user response:

One good approach is to use mode.

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

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

<xsl:template match="*" mode="addTag">
  <xsl:copy>
    <xsl:value-of select="substring(*,1,3)"/>
    <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
    <xsl:value-of select="current()"/>
    <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
  </xsl:copy>    
</xsl:template>
  • Related