Solved

XSL Style Sheet Questions

Posted on 2013-06-24
12
265 Views
Last Modified: 2013-06-25
Experts,

I have a stylesheet that has me a bit stumped, I'm new at XQuery and XSL so I apologize in advanced.  I have a style sheet, and I'm trying to capture the data in the node /DataArea/Image/Header, and create a record in the preset tags, the record should look like:

<Field Name="NAMEOFTAG" value="VALUEINTAG" pass="True"/>

So for example, if I'm looking at data that looks like:

	<DataArea>
		<Process confirm="Always" acknowledge="Never"/>
		<Image>
			<Header>
				<AppNumber>165934</AppNumber>
				<OrderNumber>613242</OrderNumber>
				<StockNumber>2724607</StockNumber>
				<Count>9</Count>
			</Header>

Open in new window


It should look similar to below in my output:

<Field Name="AppNumber" value="165934" pass="True"/>
<Field Name="OrderNumber" value="613242" pass="True"/>
<Field Name="StockNumber" value="2724607" pass="True"/>


<?xml version="1.0"?>

<!-- Begin XST Style Sheet -->


<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
	<xsl:template match="/">
    <Import>
      <Archive ConnectionID="1" Name="1">
        <Document pass="True">
          <xsl:for-each select="Pages/Page">
          <DocFile FileLoc="{@FileName}" />
          </xsl:for-each>
          <Fields>
            <xsl:for-each select="DataArea/Image/Header">
              <Field Name="{name(.)}" value="{@Value}" pass="True"/>
            </xsl:for-each>
          </Fields>
        </Document>
      </Archive>
    </Import>
	</xsl:template>
</xsl:stylesheet>

Open in new window


Any direction that could be given could be much appreciated.
0
Comment
Question by:lm1189
  • 7
  • 3
  • 2
12 Comments
 
LVL 35

Assisted Solution

by:Robert Schutt
Robert Schutt earned 167 total points
Comment Utility
Try replacing the for-each in your <Fields> output with:
            <xsl:for-each select="DataArea/Image/Header/*">
              <Field Name="{name(.)}" value="{./text()}" pass="True"/>
            </xsl:for-each>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
Hi, in the for-each you are visiting the Header element, which is only one...
you should visit the child elements on line 16
and you don't have to access the @value but the content

            <xsl:for-each select="DataArea/Image/Header/*">
              <Field Name="{name()}" value="{.}" pass="True"/>
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
Ah, you got there already

Note that you should NOT use ./text() because there is no garantuee that you will get all the content then

value="{./text()}" will put the first child text node in the value attribute. Processors or parsers can decibe to break a text content up in multiple nodes at will, so that could cause your value attribute to only be partially there

value="{.}" will take all the text nodes (including deeper nested text nodes) and serializes them as one string

It is a hot item on the list of best practices in XSLT development to avoid text() as much as you can, because it is unpredictable.
0
 
LVL 60

Assisted Solution

by:Geert Bormans
Geert Bormans earned 333 total points
Comment Utility
Given you are new, and likely willing to learn.
It is also a best practice to break up templates and use apply-templates in favour of for-each

Here is how I would write this

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:output indent="yes"/>
    
    <xsl:template match="/">
        <Import>
            <Archive ConnectionID="1" Name="1">
                <Document pass="True">
                    <xsl:apply-templates select="Pages/Page"/>
                    <Fields>
                        <xsl:apply-templates select="DataArea/Image/Header/*"/>
                    </Fields>
                </Document>
            </Archive>
        </Import>
    </xsl:template>
    
    <xsl:template match="Page">
        <DocFile FileLoc="{@FileName}" />
    </xsl:template>
    
    <xsl:template match="Header/*">
        <Field Name="{name()}" value="{.}" pass="True"/>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

0
 
LVL 35

Expert Comment

by:Robert Schutt
Comment Utility
Nice solution, Gertone.

I wonder about ./text(), it may depend on what's more likely to happen, you may need a scheme check anyway. For example if the data sent would suddenly contain
<OrderNumber>613242<BAD>True</BAD></OrderNumber>

Open in new window

then your solution concatenates the text nodes into the output which doesn't seem right either?
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
interesting for lm1189 to know indeed

using {./text()} your example would render
<Field Name="OrderNumber" value="613242" pass="True"/>
but you are never 100% sure, it could render
<Field Name="OrderNumber" value="613" pass="True"/>
depending what the XML object is and where it comes from

using {.} you are right, it would render
<Field Name="OrderNumber" value="613242True" pass="True"/>

But given this counter example
<OrderNumber><BAD>True</BAD>613242</OrderNumber>

using {./text()} this example would render
<Field Name="OrderNumber" value="" pass="True"/>
since it catches the empty whitespace text node in front of the BAD element

using {.} render
<Field Name="OrderNumber" value="True613242" pass="True"/>

Point I mainly wanted to make is that at least using '.' it is predictable

Since the XSLT is labelled 2.0
And you want to avoid child elements (I considered child elements less likely from the source than broken text nodes would be)
This one is 100% safe
       <Field Name="{name()}" value="{normalize-space(string-join(text(), ''))}" pass="True"/>
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 35

Expert Comment

by:Robert Schutt
Comment Utility
I had not considered the order but I tested and don't get the empty value, but point taken. This is great stuff, hopefully not just us looking at it ;-)
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
well, I just tested with Saxon, and indeed, it seems not all processors take the empty text node as a text() node
so
<OrderNumber><BAD>True</BAD>613242</OrderNumber>
not necessarily has a text node before the BAD, it would if there was a space or a comment or a ...
Msxml has the tendency to drop it anyhow

Interesting discussion indeed... maybe we are making lm1189 nervous now :-)
0
 

Author Comment

by:lm1189
Comment Utility
I'm not nervous.. :)

I tried the different solutions, and neither seem to work.  I've attached the sample XML file I am using as well as the XSL.  Any idea why?  Logically it makes sense, it looks like it should grab the next child node and report it back.
ND7.xsl
sample.xml
0
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 333 total points
Comment Utility
Dataarea is not the root of your document

Fix it by changing the match in the root template

  <!-- Match the root -->
  <xsl:template match="/">

should become

 <!-- Match the root -->
  <xsl:template match="ProcessImage">
0
 

Author Comment

by:lm1189
Comment Utility
Everyone, thanks for your help.  It's doing exactly as I need it, I have some other questions, I'll follow up in another post.
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
welcome
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

The Client Need Led Us to RSS I recently had an investment company ask me how they might notify their constituents about their newsworthy publications.  Probably you would think "Facebook" or "Twitter" but this is an interesting client.  Their cons…
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

744 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

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now