Solved

Select content and process child elements using XSLT

Posted on 2006-07-10
20
301 Views
Last Modified: 2013-11-19
Hello,

My XML looks like this..

<text>
Hello I am text
<child>and I am a child.</child>
more text.
</text>

I need to retrieve the content in <text> tag AND process it's child elements.

Any suggestions?

Thanks,
Kanishk.
0
Comment
Question by:kanishkpanwar
  • 14
  • 5
20 Comments
 

Author Comment

by:kanishkpanwar
ID: 17073684
there can be more than 1 child...
like <child1> <child2> etc etc
0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 17073806
Well, you would process the "text" node with something like:

    <xsl:template match="text">
        <p><xsl:value-of select="." /></p>
        <!-- Next line triggers processing of child nodes -->
        <xsl:apply-templates />
    </xsl:template>
0
 

Author Comment

by:kanishkpanwar
ID: 17073989
actually, I need the result to looks like this...

Hello I am text
<child>and I am a child.</child>
more text.
0
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 

Author Comment

by:kanishkpanwar
ID: 17074016
it could be like this too...

Hello I am text
<child>and I am a child.</child>
<child1>and I am a child1.</child1>
more text.

and so on..........
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 17074257
Hi kanishkpanwar,

if I understand you well,
this is what you need

    <xsl:template match="text">
        <xsl:copy-of select="node()|text()"/>
    </xsl:template>


Cheers!
0
 

Author Comment

by:kanishkpanwar
ID: 17074284
is there any way that I can process the child elements?

something like.....
<xsl:template match="child">
do something 1.
    </xsl:template>


<xsl:template match="child1">
do something 2.
</xsl:template>

and so on
0
 

Author Comment

by:kanishkpanwar
ID: 17074313
maybe use something like for-each?
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 17074455
no, then you would do

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

and make sure you have templates for the child nodes
(the text() will be copied anyway)

in this case it would be a good recommendation to add a mode

    <xsl:template match="text">
        <xsl:apply-templates select="node()|text()" mode="text-proc"/>
    </xsl:template>
    <xsl:template match="*" mode="text-proc">
        <!-- process the children here -->
    </xsl:template>

0
 

Author Comment

by:kanishkpanwar
ID: 17075284
will that effect my resultant XML if I already have
<xsl:template match="*"> in my XSLT ?
0
 

Author Comment

by:kanishkpanwar
ID: 17075295
I have increased the points because I have more questions and I better make it worth your time. :)
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 17075584
> will that effect my resultant XML if I already have

no, since you shield off the template from the other elements by using "mode"
there will be no conflict
0
 

Author Comment

by:kanishkpanwar
ID: 17075614
i try to process the tag <child> like this

   <xsl:element name="{local-name()}">
          <xsl:copy-of select="@*"/>
   <xsl:apply-templates />

but the <child> tag is not generated. ONLY text. :(
0
 

Author Comment

by:kanishkpanwar
ID: 17075638
</xsl:element>

is also there...missed it in copy paste.
0
 

Author Comment

by:kanishkpanwar
ID: 17075728
Here is the REAL XSLT i am working on...

<?xml version='1.0' encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns="-//FLSENATE/BILL XSD//EN">

  <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
  <xsl:preserve-space elements="ParagraphText Delete Add" />
 
 
  <xsl:template match="*">
        <xsl:choose>
              <xsl:when test="not(text()) and not(descendant::*[local-name() != 'Add'][text()])">
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="{local-name()}">
                        <xsl:copy-of select="@*"/>
                        <xsl:apply-templates />
              </xsl:element>
            </xsl:otherwise>
      </xsl:choose>
  </xsl:template>
 
  <xsl:template match="@*">
      <xsl:copy />
  </xsl:template>

  <!-- Remove Section specific attribute(s) -->
  <xsl:template match="Section">
        <xsl:element name="{local-name()}">
                  <xsl:apply-templates />
        </xsl:element>
  </xsl:template>
 
  <xsl:template match="Para">
              <xsl:element name="{local-name()}">
                     <xsl:copy-of select="@Sequence"/>
                     <xsl:copy-of select="@ParentSequence"/>
                  <xsl:apply-templates />
              </xsl:element>
  </xsl:template>

  <xsl:template match="ParaNumber">
  </xsl:template>

  <!-- Remove Section specific attribute(s) -->
  <xsl:template match="ParagraphText">
        <xsl:element name="{local-name()}">
              <xsl:variable name="PTEXT">
         <!--      <xsl:for-each select="descendant-or-self::*[name() != 'Add']/text()">-->
               <!--  <xsl:value-of select="." /> -->
               <xsl:apply-templates select="node()|text()" mode="text-proc"/>
               <!-- <xsl:apply-templates /> -->
               <!--</xsl:for-each>-->
              </xsl:variable>
              <xsl:value-of select="normalize-space($PTEXT)" />
        </xsl:element>
  </xsl:template>

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

  <!-- Remove all the added text -->
  <xsl:template match="Add">
        <xsl:text> </xsl:text>
  </xsl:template>

  <!-- Remove all the added text -->
  <xsl:template match="Add" mode="text-proc">
        <xsl:text> </xsl:text>
  </xsl:template>



  <!-- Add all the deleted text -->
  <xsl:template match="Delete" mode="text-proc">
<!--        <xsl:if test="position()&lt;last()">
          <xsl:text disable-output-escaping="yes"> </xsl:text>
          <xsl:value-of select="." />
        </xsl:if>
        <xsl:if test="position()=last()">
          <xsl:text disable-output-escaping="yes"> </xsl:text>
          <xsl:value-of select="." />
            <xsl:text disable-output-escaping="yes"> </xsl:text>
        </xsl:if>-->
    <xsl:text> </xsl:text><xsl:value-of select="." /><xsl:text> </xsl:text>
  </xsl:template>

  <xsl:template match="Delete" mode="text-proc">
<!--        <xsl:if test="position()&lt;last()">
          <xsl:text disable-output-escaping="yes"> </xsl:text>
          <xsl:value-of select="." />
        </xsl:if>
        <xsl:if test="position()=last()">
          <xsl:text disable-output-escaping="yes"> </xsl:text>
          <xsl:value-of select="." />
            <xsl:text disable-output-escaping="yes"> </xsl:text>
        </xsl:if>-->
    <xsl:text> </xsl:text><xsl:value-of select="." /><xsl:text> </xsl:text>
  </xsl:template>
 

  <!-- TO DO (Ask Yan): How to handle TypeOnly? -->
  <xsl:template match="TypeOnly">
  </xsl:template>

  <!-- TO DO (Ask Yan): Do these need to be deleted if they contain added text only? -->
  <xsl:template match="SuperScript | SubScript | Fraction | entry">
        <xsl:choose>
              <xsl:when test="not(text()) and (count(child::*) = count(child::Add))">
            </xsl:when>
            <xsl:otherwise>
              <xsl:element name="{local-name()}">
                       <xsl:copy-of select="@*"/>
                        <xsl:apply-templates />
              </xsl:element>
            </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

 <xsl:template match="SuperScript | SubScript | Fraction | entry" mode="text-proc">
        <xsl:choose>
              <xsl:when test="not(text()) and (count(child::*) = count(child::Add))">
            </xsl:when>
            <xsl:otherwise>
              <xsl:element name="{local-name()}">
                       <xsl:copy-of select="@*"/>
                        <xsl:apply-templates />
              </xsl:element>
            </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

  <xsl:template match="comment()">
  </xsl:template>

  <xsl:template match="processing-instruction()">
  </xsl:template>
 
  <xsl:template match="text()">
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:template>

</xsl:stylesheet>
0
 

Author Comment

by:kanishkpanwar
ID: 17075732
here is the XML content that needs to be translated...

<?xml version="1.0" encoding="UTF-8"?>
<Section Source="FL Statute" Selection="Section,#7/#10/#13/#523896/#523919">
      <MetaText TextInNotes="false"/>
      <SectionNumber>7.221</SectionNumber>
      <CatchLine>Glades County, <Add>HELLO </Add>extension of boundary.</CatchLine>
      <SectionBody>
            <Para Sequence="(1)" CurrentSequence="(1)" Position="Begin" Order="0">
                  <ParaNumber>(1)</ParaNumber>
                  <ParagraphText>The existing boundaries of Glades County, Florida, be, and the same are enlarged and extended so <Delete>as to comprise and</Delete> include the following described additional <Add>HELLO </Add>territory now described as follows:</ParagraphText>
            </Para>
            <Para ParentSequence="(1)" Position="Begin" Order="1">
                  <ParagraphText Type="indent" SpaceBefore="false">All that portion of the S<Fraction>1/2</Fraction>of section 32, township 39 south, range 30 east lying east of Federal Highway No. 19 in Highlands County, Florida.</ParagraphText>
            </Para>
            <Para Sequence="(2)" CurrentSequence="(2)" Position="Begin" Order="0">
                  <ParaNumber>(2)</ParaNumber>
                  <ParagraphText>Said territory herein and hereby added to Glades County, Florida, shall, after June 13, 1949, be as much a portion of said Glades County, as if originally incorporated therein.</ParagraphText>
            </Para>
      </SectionBody>
</Section>
0
 

Author Comment

by:kanishkpanwar
ID: 17075745
when I use the current XSLT....I am not able to generate <Fraction> tags...only content comes out. :)
0
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 500 total points
ID: 17076162
<xsl:element name="{local-name()}">
          <xsl:copy-of select="@*"/>
   <xsl:apply-templates />

but the <child> tag is not generated. ONLY text. :(

The problem is here:
 <!-- Remove Section specific attribute(s) -->
  <xsl:template match="ParagraphText">
        <xsl:element name="{local-name()}">
             <xsl:variable name="PTEXT">
         <!--     <xsl:for-each select="descendant-or-self::*[name() != 'Add']/text()">-->
             <!--  <xsl:value-of select="." /> -->
             <xsl:apply-templates select="node()|text()" mode="text-proc"/>
             <!-- <xsl:apply-templates /> -->
              <!--</xsl:for-each>-->
             </xsl:variable>
             <xsl:value-of select="normalize-space($PTEXT)" />
        </xsl:element>
  </xsl:template>

you store the text and the childnodes in a variable
and then you do an value-of select, which only gives you back the text content, not the childnodes

it is generally not a good idea to manipulate the whitespace nodes like this in XSLT
try to be cautious with the existing whitespace nodes,
or strip them all and add your own

cheers

0
 

Author Comment

by:kanishkpanwar
ID: 17076316
yeah...
I removed the variable bit and now the white space after "</Fraction> out" is getting lost. :(

MAN ! I am sooo tired...
0
 

Author Comment

by:kanishkpanwar
ID: 17076545
I think i'll do some research on my own and post a new question, IF needed.

thanks A LOT gertone for your help. :)
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 17076675
welcome, cheers
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is Node.js? Node.js is a server side scripting language much like PHP or ASP but is used to implement the complete package of HTTP webserver and application framework. The difference is that Node.js’s execution engine is asynchronous and event…
JavaScript has plenty of pieces of code people often just copy/paste from somewhere but never quite fully understand. Self-Executing functions are just one good example that I'll try to demystify here.
The viewer will learn how to count occurrences of each item in an array.
The viewer will the learn the benefit of plain text editors and code an HTML5 based template for use in further tutorials.

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question