lm1189
asked on
XSL Style Sheet Questions
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:
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"/>
Any direction that could be given could be much appreciated.
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>
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>
Any direction that could be given could be much appreciated.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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>
then your solution concatenates the text nodes into the output which doesn't seem right either?
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</BA D>613242</ OrderNumbe r>
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(st ring-join( text(), ''))}" pass="True"/>
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</BA
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(st
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 ;-)
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</BA D>613242</ OrderNumbe r>
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 :-)
so
<OrderNumber><BAD>True</BA
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 :-)
ASKER
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
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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
welcome
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/Hea
<Field Name="{name()}" value="{.}" pass="True"/>