Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old March 11th, 2009, 08:44 PM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default Problem sorting data to give svg path

Dear all.

I have nearly completed a mini project to display slope (geotechnical engineering) information in the form of an SVG cross section (as well as many other elements).

I am desperately close to the finish line but have a problem which could be altered in one or two ways I think, however I cannot figure it out (not experienced enough). I apologise if the code shown here isn't great...but it works other than this!

The XML data relevant to this part will be held as:
Code:
<geo:case caseID="ID1">
    <geo:slope>
          <geo:groundLayers>
                <diggs:layers diggs:id="1">
                    <diggs:layer>
                        <geo:location>
                            <gml:Point gml:id="1">
                                <gml:pos>316865 504940</gml:pos>
                            </gml:Point>
                            <geo:Height>749</geo:Height>
                            <diggs:top>200</diggs:top>
                        </geo:location>
                    </diggs:layer>
                    <diggs:layer>
                        <geo:location>
                            <gml:Point gml:id="level2Point1">
                                <gml:pos>316570 505159</gml:pos>
                            </gml:Point>
                            <geo:Height>450</geo:Height>
                            <diggs:top>150</diggs:top>
                        </geo:location>
                    </diggs:layer>
                </diggs:layer>
           </diggs:layers>
           <diggs:layers diggs:id="2">
                     ...
                     ...
<diggs:layers> then appears any number of times (with new diggs:id) and again will contain any number of <diggs:layer> elements. Essentially what this is storing is information regarding a coordinate (Easting and Northing), an altitude (above/below sea level) and <diggs:top> holds the depth in metres to a soil ground layer. Each diggs:layers id represents a new ground (sub-strata) level (found by a borehole). Each <diggs:layer> within <diggs:layers> will essentially be plotting a point on a path for the cross section.

Here is a function I have at the bottom:
Code:
  <!-- Ground Layer Function -->
  <xsl:function name="geo:point3" as="xs:integer+">
    <xsl:param name="location3" as="element(diggs:layer)"/>
    <xsl:variable name="point3" as="xs:string" select="$location3/geo:location/gml:Point/gml:pos"/>
    <xsl:sequence select="xs:integer(substring-before($point3, ' '))"/>
    <xsl:sequence select="xs:integer(substring-after($point3, ' '))"/>
  </xsl:function>
This splits up the coordinate tuple so that each individual coordinate can be held as Easting or Northing so that things can be calculated to show the image.

Here are the variables required for this part (and utilises the function above):
Code:
    <!-- Ground layer variables -->
    <xsl:variable name="groundLayers" as="element(groundLayer)+">
      <xsl:for-each select="geo:slope/geo:groundLayers/diggs:layers/diggs:layer">
        <!--<xsl:sort select="parent::geo:location/parent::diggs:layer/parent::diggs:layers/@diggs:id" order="descending"/>-->
        <xsl:variable name="groundLayer" as="xs:integer+" select="geo:point3(.)"/>
        <xsl:variable name="coordinateX1" as="xs:integer" select="$groundLayer[1]"/>
        <xsl:variable name="coordinateY1" as="xs:integer" select="$groundLayer[2]"/>

        <xsl:variable name="c2" as="xs:decimal" select="$groundLayer[2] - (($m2)*$groundLayer[1])"/>
        <xsl:variable name="cdiff" as="xs:decimal" select="$c1 - $c2"/>
        <xsl:variable name="xi" as="xs:decimal" select="$cdiff div $mdiff"/>
        <xsl:variable name="yi" as="xs:decimal" select="($m2*$xi)+$c2"/>
        <xsl:variable name="xdiff" as="xs:decimal" select="$toe[1] - $xi"/>
        <xsl:variable name="ydiff" as="xs:decimal" select="$toe[2] - $yi"/>
        <xsl:variable name="distanceGL" as="xs:decimal"
          select="xs:integer(round(math:sqrt($ydiff * $ydiff + $xdiff * $xdiff)))"/>

        <xsl:variable name="heightGL" as="xs:integer" select="geo:location/geo:Height"/>
        <xsl:variable name="altitudeGL" as="xs:integer">
          <xsl:choose>
            <xsl:when test="$altitude[1] &lt; 0">
              <xsl:value-of select="$altitude[1]+$heightGL"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$heightGL - $altitude[1]"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>

        <xsl:variable name="layerTopDepth" as="xs:integer" select="geo:location/diggs:top"/>
        <xsl:variable name="layerId" select="@id" />

        <groundLayer xmlns="">
          <distanceGL>
            <xsl:value-of select="$distanceGL"/>
          </distanceGL>
          <altitudeGL>
            <xsl:value-of select="$altitudeGL"/>
          </altitudeGL>
          <heightGL>
            <xsl:value-of select="$heightGL"/>
          </heightGL>
          <coordinateX1>
            <xsl:value-of select="$coordinateX1"/>
          </coordinateX1>
          <coordinateY1>
            <xsl:value-of select="$coordinateY1"/>
          </coordinateY1>
          <layerTopDepth>
            <xsl:value-of select="$layerTopDepth"/>
          </layerTopDepth>
          <layerId>
            <xsl:value-of select="$layerId" />
          </layerId>
        </groundLayer>
      </xsl:for-each>
    </xsl:variable>
There is a lot calculated there I know..sorry! It is all needed though.

So the important part here is the <xsl:for-each select="geo:slope/geo:groundLayers/diggs:layers/diggs:layer">. This means that it is looping within <diggs:layer> and performing the function shown earlier to help calculate the variables.

Ok so my problem: I need to now split all of the data from this in to each <diggs:layers>, per each diggs:id. In my test example I have two layers (so diggs:id's of 1 and 2). Once these are split up I need them to be sorted in a descending order by id.

I tried doing the above by using a for-each loop (over the <diggs:layers>) when it came to stating the SVG path. If I do then I receive an error because I need <xsl:for-each select="$groundLayers"> in order to access my variable information.

My alternative idea was to change the variable's <for-each> loop to looping over <diggs:layers> as this would be ideal! The problem is that there are multiple coordinate tuples found in each sub structure of that level and so the function I showed earlier fails because it is looking for 2 points. (I need to cater for unlimited.)

If anyone has any questions that need answering in order to help me then please do! It's hard to explain this work I'm sorry.

Oh, the calculations etc are all correct and I can plot each point as an svg circle held in that xml structure shown at the top. This means that the data is accessed and calculated ok, it's just a matter of separating them up so that these calculations still work, but the 'answer' coordinates are grouped as per the diggs:layers diggs:id they came from.

Thank you for reading this far!
James

edit:
here's my code for the path at the moment:
Code:
    <xsl:for-each select="$groundLayers[1]">
         <path stroke="blue" stroke-width="2" fill="none">
            <xsl:attribute name="d">
              <xsl:text>M</xsl:text>
              <xsl:value-of select="$distance - distanceGL"/>
              <xsl:text> </xsl:text>
              <xsl:value-of select="$height - altitudeGL + layerTopDepth"/>
              <xsl:text> L </xsl:text>
              <xsl:for-each select="$groundLayers">
                <xsl:sort select="xs:double(distanceGL)" order="descending"/>
                <xsl:value-of
                  select="concat($distance - distanceGL, ' ', $height - altitudeGL + layerTopDepth)"/>
                <xsl:if test="position() != last()">
                  <xsl:text>, </xsl:text>
                </xsl:if>
              </xsl:for-each>
            </xsl:attribute>
          </path>
I used the predicate [1] in the for-each loop so as to just show 1 output path (as in my full xml files I have 2 <diggs:layers> and 4 <diggs:layer> elements within each...giving 8 loops from the variables and therefore 8 paths). This one output path gives the following:
Code:
 <path stroke="blue" stroke-width="2" fill="none"
                        d="M0 200 L 0 200, 0 0, 363 449, 363 299, 574 599, 574 499, 901 599, 901 549"/>
This is almost correct as I've explained before. Basically because the two <diggs:layers> are not grouped separately and therefore drawn in to two different paths, they have performed one iteration and sorted by my current sorting factor (which needs to remain on top of the proposed grouping). After 'L' (in the path) every second coordinate needs to be removed and put in to a new path. So my desired output would be (make comparison):
Code:
<path stroke="blue" stroke-width="2" fill="none"
                        d="M0 200 L 0 200, 363 449, 574 599, 901 599"/>
<path stroke="blue" stroke-width="2" fill="none"
                        d="M0 0 L 0 0, 363 299, 574 499, 901 549"/>
Here is an image of my stripped down code (to just focus on this problem) plotting each point as a circle (which therefore is to test that all the correct points have been calculated, which they have, however they need to be sorted and grouped in order to draw the paths correctly and separately). To show each point I removed the predicate [1] from the for-each.
http://i3.photobucket.com/albums/y90...icture1-24.png

And here is the image path shown with the code shown on this page (using predicate). Now that the top line of points and the bottom line of points should be drawn with 2 separate paths...not joined together.
http://i3.photobucket.com/albums/y90...icture2-12.png

Last edited by jamesdurham; March 11th, 2009 at 09:01 PM.. Reason: Extra information added
 
Old March 12th, 2009, 07:06 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

You've given a lot of information and I'm not sure I've grasped it all.

>Ok so my problem: I need to now split all of the data from this in to each <diggs:layers>, per each diggs:id. In my test example I have two layers (so diggs:id's of 1 and 2). Once these are split up I need them to be sorted in a descending order by id.

It seems to me that by doing a simple for-each over the leaf diggs:layer elements, you've thrown away information about their hierarchic relationship that you actually need to retain. Instead of creating a flat sequence of groundLayer elements, you should perhaps create an augmented version of the original tree structure, copying the original nodes but adding computed information about the coordinates. The way to create this augmented tree is by doing a tree traversal using xsl:apply-templates in a recursive descent, copying all the element nodes as you go.

Another approach would be to flatten the data as you have done, but retaining extra attributes that allow you to rebuild the hierarchy as a grouping operation. But I don't really see the point of that.

It's also possible that you don't really need a multiphase approach at all (i.e. you don't need the temporary data structure with computed values, whether it's a flat sequence or a tree) and can create your output directly form the original input. That demands a better understanding of what you are finally doing with the data than I have at the moment.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old March 12th, 2009, 09:23 AM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by mhkay View Post
You've given a lot of information and I'm not sure I've grasped it all.
Sorry I had to give so much information. I may highlight the main concepts of what's happening at the bottom of this post.

Quote:
Originally Posted by mhkay View Post
It seems to me that by doing a simple for-each over the leaf diggs:layer elements, you've thrown away information about their hierarchic relationship that you actually need to retain. Instead of creating a flat sequence of groundLayer elements, you should perhaps create an augmented version of the original tree structure, copying the original nodes but adding computed information about the coordinates. The way to create this augmented tree is by doing a tree traversal using xsl:apply-templates in a recursive descent, copying all the element nodes as you go.
That's exactly the cause of my problem! Unfortunately it's the only method I understand that can create variables that have a string splitting function used on them. And the method I used for holding that new variable data (i.e. within the same for-each loop and variable loop) is the only one I know and seemed to be required when using a for-each loop for declaring variables as the variables were then not accessible globally without it. It has been awkward at times with other scenarios but has worked in the end for me.

The augmented tree structure sounds ideal but I am hoping there's a less intensive task (as I don't know if I could handle it without help).

Quote:
Originally Posted by mhkay View Post
Another approach would be to flatten the data as you have done, but retaining extra attributes that allow you to rebuild the hierarchy as a grouping operation. But I don't really see the point of that.
If I understand what you are saying here correctly then this sounds like it could be a solution to my problem and perhaps involve less work? What method could I implement in order to retain, somehow, and then group, the information of what <diggs:layer> element's parent (<diggs:layers>) id is?


Quote:
Originally Posted by mhkay View Post
It's also possible that you don't really need a multiphase approach at all (i.e. you don't need the temporary data structure with computed values, whether it's a flat sequence or a tree) and can create your output directly form the original input. That demands a better understanding of what you are finally doing with the data than I have at the moment.
Unfortunately I just couldn't think of another way in which I could perform those calculations *and* split the strings tuples up.


Ok I'm going to try and explain a little clearer about what I think may be needed:

The variables are created using the substring before/after function. This means that I am only allowed to access strings of two (or a known length?) and it will split them in to two numbers for me so that the calculations can be run using each individually. Because of the constraint relating to substring before/after technique, I am unable to for-each loop over the desired level (i.e <diggs:layers> in order to retain the diggs:id they each have) because I receive an error stating that there are essentially more points within that level than the substring function can handle.

A possible solution I could think of for this was by changing the substring function to a tokenize function which could then split up each coordinate pair but also deal with as many coordinate pairs as are found within each <diggs:layers> (which could vary from 1 to 10 or so). My attempts to do this failed unfortunately. Maybe though someone here could adjust my function shown in my original post to be a tokenize function that works like this? Just remembering though that it has to be able to handle 1 coordinate pair, or anything up to 10 or so.

A possible solution I thought may work (but hasn't for me thus far) was to leave the variable looping and calculation as they are (as they do give me the desired output, just without desired flexibility for anyhow usage), and to try and work out a way or sorting/grouping the values at the point of drawing the paths. The problems I encounter here are:
-if I do a for-each loop and select to loop over the desired <diggs:layers> and then sort by id (which would in theory give me as many paths as are diggs:layers elements) then I receive errors because it cannot understand the variables found within my variable loop. The only way I can access those variables is by choosing $groundLayers as my for-each select attribute and not diggs:layers. This then loops over the same level as the $groundLayers which was one level down and will produce too many paths and not allow me to sort by the parent id's mentioned above.

-In a desparate move I thought that I could maybe encapsulate this for-each $groundLayers path loop inside another for-each loop (this time over the desired level of diggs:layers) but this just generates the same output as before just then repeats it as many time as are diggs:layers elements!


SO! Basically there's 2 options in my mind that I'd like looking at:
1) Could the tokenize function help me? The variable looping would now occur over the correct tree level in order to maintain the id's for which I wish to sort by and generate paths for. I would just need the variable calculations to still work and hold the information as they do now...

2)Or, to adjust how the variables are held. This would be so that they were accessible globally and I could then create paths <for-each select="diggs:layers"> and sort by id. As mentioned before, the variables are only accessible through selecting <for-each select="$groundLayers">, which then doesn't give me the flexibilty to then loop over the desired level


Thanks for any help that is or can be given...it's a worthwhile cause of trying to unite slope and slope stability information across the web and get it to view certain general information without entering in to a software package.
edit: I'm working in Oxygen and using Saxon-B 9.1.0.3 to transform my xml using the xsl file. This can handle the XSLT 2.0 as far as I know

Last edited by jamesdurham; March 12th, 2009 at 09:32 AM..
 
Old March 12th, 2009, 10:33 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

You've got some mental block about the string splitter function, and I can't quite see where your difficulty lies. There's some concept you've misunderstood, and I don't know what it is!

You can change your code to create an augmented hierarchy by changing

Code:
<xsl:for-each select="slope/groundLayers/layers/layer">
to

Code:
<xsl:for-each select="slope">
  <slope>
     <xsl:for-each select="groundLayers">
        <groundLayers>
           <xsl:for-each select="layers">
              <layers>
                 <xsl:for-each select="layer">
and of course you can copy whatever attributes etc you want to retain at each level. (I would do it using apply-templates rather than nested for-each, but thats inessential). Then inside the innermost for-each, your context node is a layer as it was before, so you can do the same as you did before, which will add a groundLayer element containing computed values as a child of each layer element. And of course you can retain the existing children of the layer element (by xsl:copy-of) if you want to.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
The Following User Says Thank You to mhkay For This Useful Post:
jamesdurham (March 13th, 2009)
 
Old March 12th, 2009, 11:17 AM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default

Thanks again for your reply.

You are probably correct about me misunderstanding some area of the string splitting functions. Unfortunately I had to learn XSLT, XML, SVG, Javascript and some PHP in order succeed in this project and in trying to reach high finishing standards I have probably misunderstood some more technical programming concepts within XSLT. I do wish I had more time on it in order to get the quality that I like to achieve but at the moment I have to get enough desired output to satisfy the project. (Later I could always come back and sort it out somewhat.)

Thanks for explaining the augmented layout - I shall attempt that now and post back my results if that's ok.

edit: Sorry for sounding stupid but may I just clarify your exact meaning with the augmented hierarchy?

Quote:
Originally Posted by mhkay
Code:
---------
<xsl:for-each select="slope/groundLayers/layers/layer">
---------
to


Code:
---------
<xsl:for-each select="slope">
<slope>
<xsl:for-each select="groundLayers">
<groundLayers>
<xsl:for-each select="layers">
<layers>
<xsl:for-each select="layer">
---------
Here is something I quickly changed to, based on what you said:
Code:
<!-- Ground layer variables -->
    <xsl:variable name="groundLayers" as="element(groundLayer)+">
      <!--<xsl:for-each select="geo:slope/geo:groundLayers/diggs:layers/diggs:layer">-->
      <!--<xsl:sort select="parent::geo:location/parent::diggs:layer/parent::diggs:layers/@diggs:id" order="descending"/>-->
      <xsl:for-each select="geo:slope">
        <slope>
          <xsl:for-each select="geo:groundLayers">
            <groundLayers>
              <xsl:for-each select="diggs:layers">
                <layers>
                  <xsl:for-each select="diggs:layer">
                    <layer>
                      <xsl:variable name="groundLayer" as="xs:integer+" select="geo:point3(.)"/>
                      <xsl:variable name="coordinateX1" as="xs:integer" select="$groundLayer[1]"/>
                      <xsl:variable name="coordinateY1" as="xs:integer" select="$groundLayer[2]"/>

                      <xsl:variable name="c2" as="xs:decimal"
                        select="$groundLayer[2] - (($m2)*$groundLayer[1])"/>
                      <xsl:variable name="cdiff" as="xs:decimal" select="$c1 - $c2"/>
                      <xsl:variable name="xi" as="xs:decimal" select="$cdiff div $mdiff"/>
                      <xsl:variable name="yi" as="xs:decimal" select="($m2*$xi)+$c2"/>
                      <xsl:variable name="xdiff" as="xs:decimal" select="$toe[1] - $xi"/>
                      <xsl:variable name="ydiff" as="xs:decimal" select="$toe[2] - $yi"/>
                      <xsl:variable name="distanceGL" as="xs:decimal"
                        select="xs:integer(round(math:sqrt($ydiff * $ydiff + $xdiff * $xdiff)))"/>

                      <xsl:variable name="heightGL" as="xs:integer" select="geo:location/geo:Height"/>
                      <xsl:variable name="altitudeGL" as="xs:integer">
                        <xsl:choose>
                          <xsl:when test="$altitude[1] &lt; 0">
                            <xsl:value-of select="$altitude[1]+$heightGL"/>
                          </xsl:when>
                          <xsl:otherwise>
                            <xsl:value-of select="$heightGL - $altitude[1]"/>
                          </xsl:otherwise>
                        </xsl:choose>
                      </xsl:variable>

                      <xsl:variable name="layerTopDepth" as="xs:integer"
                        select="geo:location/diggs:top"/>
                      <xsl:variable name="layerId" select="@id"/>

                      <groundLayer xmlns="">
                        <distanceGL>
                          <xsl:value-of select="$distanceGL"/>
                        </distanceGL>
                        <altitudeGL>
                          <xsl:value-of select="$altitudeGL"/>
                        </altitudeGL>
                        <heightGL>
                          <xsl:value-of select="$heightGL"/>
                        </heightGL>
                        <coordinateX1>
                          <xsl:value-of select="$coordinateX1"/>
                        </coordinateX1>
                        <coordinateY1>
                          <xsl:value-of select="$coordinateY1"/>
                        </coordinateY1>
                        <layerTopDepth>
                          <xsl:value-of select="$layerTopDepth"/>
                        </layerTopDepth>
                        <layerId>
                          <xsl:value-of select="$layerId"/>
                        </layerId>
                      </groundLayer>
                    </layer>
                  </xsl:for-each>
                </layers>
              </xsl:for-each>
            </groundLayers>
          </xsl:for-each>
        </slope>
      </xsl:for-each>
    </xsl:variable>
I receive an error:
F [Saxon-B 9.1.0.3] Required item type of value of variable $groundLayers is element(groundLayer, xs:anyType); supplied value has item type element({http://www.w3.org/2000/svg}slope, {http://www.w3.org/2001/XMLSchema}untyped)

Do I have the right idea here? All I have done is broken down the for-each loop's select XPath location from before and created this augmented hierarchy down to the level where the variable calculations can be performed as before. I guess that this would then let me use information held at any point within this hierarchy? So along with perhaps identifying the above error, how would I go about capturing an attribute i.e. how would I capture the attribute diggs:id="x" (where x is an integer and this attribute is taken from <diggs:layers>) at the new augmented hierarchy stage of <layers> ?

I guess I can then, when drawing the path further down, call <for-each select="$groundLayers"> and then sort them by the diggs:id (I just mentioned) and then use the data held by the variables at the augmented hierarchy low level of <layer>.

?

Thanks


edit2:
To add the attribute at the <layers> stage, would add this xsl:attribute in to here:
Code:
<xsl:for-each select="diggs:layers">
                <layers>
                  <xsl:attribute name="diggs:id">
                    <xsl:value-of select="@id" />
                  </xsl:attribute>
                  <xsl:for-each select="diggs:layer">
                    <layer>.....
?

Last edited by jamesdurham; March 12th, 2009 at 12:08 PM.. Reason: more info added
 
Old March 12th, 2009, 12:33 PM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default Perhaps read this one instead!

Sorry but I changed a few things and I no longer receive any errors. However my output is blank and so the variables are not being accessed by the <path> function. I do get two paths in the output though (even if they are blank) which shows that it's now looping over the correct sections...just can't 'see' the calculated data. Must be close...

Here's my augmented hierarchy, now error free but I'm sure there's something wrong!
Code:
<xsl:variable name="groundLayers" as="element(layers)+">
    <xsl:for-each select="geo:slope/geo:groundLayers/diggs:layers">
       <xsl:variable name="layerId" select="@diggs:id" as="attribute()"/>
                <layers xmlns="">
                  <xsl:value-of select="layerId"/>
                  <xsl:for-each select="diggs:layer">
                      <xsl:variable name="groundLayer" as="xs:integer+" select="geo:point3(.)"/>
                      <xsl:variable name="coordinateX1" as="xs:integer" select="$groundLayer[1]"/>
                      <xsl:variable name="coordinateY1" as="xs:integer" select="$groundLayer[2]"/>

                      <xsl:variable name="c2" as="xs:decimal"
                        select="$groundLayer[2] - (($m2)*$groundLayer[1])"/>
                      <xsl:variable name="cdiff" as="xs:decimal" select="$c1 - $c2"/>
                      <xsl:variable name="xi" as="xs:decimal" select="$cdiff div $mdiff"/>
                      <xsl:variable name="yi" as="xs:decimal" select="($m2*$xi)+$c2"/>
                      <xsl:variable name="xdiff" as="xs:decimal" select="$toe[1] - $xi"/>
                      <xsl:variable name="ydiff" as="xs:decimal" select="$toe[2] - $yi"/>
                      <xsl:variable name="distanceGL" as="xs:decimal"
                        select="xs:integer(round(math:sqrt($ydiff * $ydiff + $xdiff * $xdiff)))"/>

                      <xsl:variable name="heightGL" as="xs:integer" select="geo:location/geo:Height"/>
                      <xsl:variable name="altitudeGL" as="xs:integer">
                        <xsl:choose>
                          <xsl:when test="$altitude[1] &lt; 0">
                            <xsl:value-of select="$altitude[1]+$heightGL"/>
                          </xsl:when>
                          <xsl:otherwise>
                            <xsl:value-of select="$heightGL - $altitude[1]"/>
                          </xsl:otherwise>
                        </xsl:choose>
                      </xsl:variable>

                      <xsl:variable name="layerTopDepth" as="xs:integer"
                        select="geo:location/diggs:top"/>

                      <groundLayer>
                        <distanceGL>
                          <xsl:value-of select="$distanceGL"/>
                        </distanceGL>
                        <altitudeGL>
                          <xsl:value-of select="$altitudeGL"/>
                        </altitudeGL>
                        <heightGL>
                          <xsl:value-of select="$heightGL"/>
                        </heightGL>
                        <coordinateX1>
                          <xsl:value-of select="$coordinateX1"/>
                        </coordinateX1>
                        <coordinateY1>
                          <xsl:value-of select="$coordinateY1"/>
                        </coordinateY1>
                        <layerTopDepth>
                          <xsl:value-of select="$layerTopDepth"/>
                        </layerTopDepth>
                        <layerId>
                          <xsl:value-of select="$layerId"/>
                        </layerId>
                      </groundLayer>
                  </xsl:for-each>
                </layers>
      </xsl:for-each>
      </xsl:variable>
And here's the <path> function aimed at using this information:
Code:
<xsl:for-each select="$groundLayers">
            <path stroke="blue" stroke-width="2" fill="none">
              <xsl:attribute name="d">
                <xsl:text>M</xsl:text>
                <xsl:value-of select="$distance - distanceGL"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="$height - altitudeGL + layerTopDepth"/>
                <xsl:text> L </xsl:text>
                <xsl:for-each select="$groundLayers">
                  <xsl:sort select="xs:double(distanceGL)" order="descending"/>
                  <xsl:value-of
                    select="concat($distance - distanceGL, ' ', $height - altitudeGL + layerTopDepth)"/>
                  <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                  </xsl:if>
                </xsl:for-each>
              </xsl:attribute>
            </path>
        </xsl:for-each>
Output is:
Code:
<path stroke="blue" stroke-width="2" fill="none" d="M  L  ,  "/>
<path stroke="blue" stroke-width="2" fill="none" d="M  L  ,  "/>

Last edited by jamesdurham; March 12th, 2009 at 01:15 PM.. Reason: improved code
 
Old March 12th, 2009, 01:18 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

You have typed your 'groundLayers' variable as element(slope)+ so you are processing a sequence of 'slope' elements with the outer xsl:for-each.
I think instead of the inner
Code:
<xsl:for-each select="$groundLayers">
you want/need
Code:
<xsl:for-each select="groundLayers/layers/layer/groundLayer">
That is a guess based on the hierarchy you store in your variable but with that expression your would at least process elements in your inner for-each that have child elements like 'distanceGL' you try to access in the other expressions.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old March 12th, 2009, 01:34 PM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default

Note: I edited my previous post and cut down on some of the unneeded new elements. The variable structure (on the surface) achieves what I would like it to now but my problem still exists with getting the paths to print values.

Quote:
Originally Posted by Martin Honnen
I think instead of the inner

Code:
---------
<xsl:for-each select="$groundLayers">
---------
you want/need

Code:
---------
<xsl:for-each select="groundLayers/layers/layer/groundLayer">
---------
Unfortunately (even adjusting for my new hierarchy) that doesn't seem to work. I now don't even receive even a blank <path> output. My update to your suggestion (and what I tried) was:
Code:
<xsl:for-each select="layers/groundLayer">
<path stroke="blue" stroke-width="2" fill="none">
              <xsl:attribute name="d">
                <xsl:text>M</xsl:text>
                <xsl:value-of select="$distance - distanceGL"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="$height - altitudeGL + layerTopDepth"/>
                <xsl:text> L </xsl:text>
                <xsl:for-each select="$groundLayers">
                  <xsl:sort select="xs:double(distanceGL)" order="descending"/>
                  <xsl:value-of
                    select="concat($distance - distanceGL, ' ', $height - altitudeGL + layerTopDepth)"/>
                  <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                  </xsl:if>
                </xsl:for-each>
              </xsl:attribute>
            </path>
The reason I don't think that this works is because I need to access the variable $groundLayers before I can then move about it using XPath - how I do that in one expression I don't know? But currently by putting that for-each select path in it is looking for it as a child of something within original XML file, which this is not as we have just created it within the groundLayers variable.

Cheers

edit: even if that method did print out values within path elements, it would not achieve what I need it to as I need as many <path>'s as there are <diggs:layers> elements. By narrowing down that for-each selection it would, i think, create as many paths as there are groundLayer elements, which would be many and incorrect.

So the question is, how come it is looping correctly for the paths but not finding the output generated within $groundLayers? Output like distanceGL and altitudeGL should be found as they were before with the same hierarchy, it's just that now the hierarchy runs deeper.

Last edited by jamesdurham; March 12th, 2009 at 01:43 PM..
 
Old March 12th, 2009, 01:40 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

You have not understood what I suggested. I suggested to replace the inner for-each while you have now changed the outer for-each.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old March 12th, 2009, 01:55 PM
Authorized User
 
Join Date: Mar 2009
Posts: 50
Thanks: 7
Thanked 0 Times in 0 Posts
Default

I'm sorry.

It still has not worked. The ouput now gives:
Code:
         <path stroke="blue" stroke-width="2" fill="none" d="M  L "/>
         <path stroke="blue" stroke-width="2" fill="none" d="M  L "/>
It therefore is not recognising the XPath select="layers/GroundLayer"

Here is what I changed it to:
Code:
         <xsl:for-each select="$groundLayers">
            <path stroke="blue" stroke-width="2" fill="none">
              <xsl:attribute name="d">
                <xsl:text>M</xsl:text>
                <xsl:value-of select="$distance - distanceGL"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="$height - altitudeGL + layerTopDepth"/>
                <xsl:text> L </xsl:text>
                <xsl:for-each select="layers/groundLayer">
                  <xsl:sort select="xs:double(distanceGL)" order="descending"/>
                  <xsl:value-of
                    select="concat($distance - distanceGL, ' ', $height - altitudeGL + layerTopDepth)"/>
                  <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                  </xsl:if>
                </xsl:for-each>
              </xsl:attribute>
            </path>
I didn't think it would make a difference because above that inner for-each loop there's already a mention of some of those elements that you are saying will need locating for the inner loop to work.

The thing is though that I do need it all to loop over the top level of the variable $groundLayers. If it loops through groundLayer then it will not perform things correctly.

At the top of this page (my original post here) I was able to access the data by using that for-each loop of $groundLayers and the data was then held at the level "groundLayer/....". All I have essentially done now is add in one more level to the hierarchy, so why would it not be able to see them as before it skipped 'groundLayer' and found the level below such as 'distanceGL'. I need that one extra layer for the original purposes of only drawing as many SVG paths as there are <diggs:layers> elements.





Similar Threads
Thread Thread Starter Forum Replies Last Post
Can anyone give me some sample data? kinzlaw BOOK: Beginning Visual Basic 2005 Databases ISBN: 978-0-7645-8894-5 7 June 19th, 2007 05:04 AM
Implementing the all-path shortest path problem bitwords XSLT 1 December 6th, 2006 11:37 AM
SVG viewer 3.03 hyperlink problem gps Ajax 0 August 9th, 2006 11:01 AM
pls give the query for XML data in Sqlserver2005 veeruu SQL Server 2005 0 July 27th, 2006 05:07 AM
pls give query to diplay XML data in Sqlserver2005 veeruu XML 0 July 27th, 2006 05:06 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.