I get the following error after my xslt has been processed:
There are 1 schema validation error(s):
1. Error Msg:The element 'BusinessObjectList' has incomplete content. List of possible elements expected: 'BusinessObject'. Line Number: 1, Line Position: 40, Severity:Error
I am trying to troubleshoot this issue and just require some clarifications. From my understanding of this error, there is a missing element called BusinessObject. So, I am not too sure if i have to incorporate this missing element or replace the existing element with this? another question too is, how to refer to Line 1, Line Position 40 in my xslt file?
Below is how the beginning of the xslt looks like:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
<BusinessObjectList SchemaVersion="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="HierarchicalObjects-1.0.xsd">
You haven't told us how you are running the transformation, but it seems to be configured so that on completion the result document is validated against the schema at HierarchicalObjects-1.0.xsd. Presumably that schema says that the BusinessObjectList must contain at least N BusinessObject elements (perhaps N is 1, we don't know), and your transformation output includes less than N.
You either need to produce output that conforms to the schema, or you need to change the way you are processing to avoid the validation step.
The line/column number probably refers to a line/column in the result document, not in the stylesheet.
this is a self-answered post, since it took me some time to find the reason for the following XTSE0120.
I'm quite new to XSLT and made a mistake and put some text outside <xsl:template>:
bellack#bellack-TP-T430u:~$ cat -n /tmp/x.xsl
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <xsl:stylesheet
3 version="2.0"
4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 >
6 <xsl:output method="text"/>
7 <xsl:template name="build" match="/">
8 <!--
9 a lot of xslt code lines
10 -->
11 </xsl:template>
12 ****** misplaced text ****************
13 </xsl:stylesheet>
As this is not allowed, I got error XTSE120, see http://www.w3.org/TR/xslt-30/#err-XTSE0120:
bellack#bellack-TP-T430u:~/workspace/tembanking/generator/crud$ java -jar ../lib/saxon9.jar -xsl:/tmp/x.xsl -s:/dev/null
Error at xsl:template on line 7 of file:/tmp/x.xsl:
XTSE0120: No character data is allowed between top-level elements
Failed to compile stylesheet. 1 error detected.
But the Error is reported for line 7, and since x.xsl had some hundred lines, I was searching for something wrong around line 7 in vain, where the error was in fact at the end of the file.
I don't know if other XSLT processors than saxon also give this misleading error message.
Hope that helps somebody ...
Udo
Saxon only keeps line number information for element nodes, not for text nodes, so we have difficulty reporting an accurate position for the rare case where the error is in a text node.
Lets say I have the following xml.
<root>
<data>
<a>ATTITUDE_ANNOYED</a>
<b>ATTITUDE_CAUTIOUS</b>
<c>25</c>
<d>30</d>
</data>
</root>
Ignoring the schema of my output, I want my output to present A as "Cautious" (one level up from annoyed), B as "
Pleased" (one level up from Cautious") and I want to perform some maths on C and D to convert the value into something slightly different.
I've had a look at a bunch of similar questions here (and I'm new to XSLT so maybe I don't quite get it) but a lot of the solutions appear to be "in-line", i.e. you modify the result as you transform it. This is okay but in my real example there are a lot of these values and I don't want to be performing the exact same conversion in multiple places (DRY). I just want to more or less pre-process the entire document and convert a bunch of values into other values (using just a few formulas) before I start the transformation.
What would be the best way to achieve this? I'm not particularly interested in performance so is there a way that I can run a prior transformation to easily transform specific values without modifying the structure?
UPDATE: (DevNull asked for my output desires) The output isn't exactly finalised. I'm trying to help a group at CivFanatics produce a guide on the differences between the AIs whose values derive from an xml file. There are a ton of leaders and a ton of values that need converting, by hand its taking them 2 hours per leader at the moment and the final formatting hasn't been decided on so I thought we'd all save time by using something like XLST.
Here is a rough example of a demo I'm working on.
<xsl:template match="data">
<h3>Attitude Thresholds</h3>
<table border="1">
<tr><td>Will open borders</td><td><xsl:value-of select="a"/></td></tr>
<tr><td>Will trade techs</td><td><xsl:value-of select="b"/></td></tr>
</table>
</xsl:template>
To clarify A and B are OpenBordersRefuseAttitudeThreshold and TechRefuseAttitudeThreshold. The guide is more readable if these are WillOpenBordersAt and WillTradeTechAt as opposed to the original values in the xml file so I need to nudge them up a value for the final output.
There are additional conversions that have been discussed:
iWonderConstructRand -> Builds Wonders
0 -> 0/10
5 -> 1/10
10 -> 2/10
15 -> 3/10
20 -> 4/10
25 -> 5/10
30 -> 6/10
35 -> 7/10
40 -> 8/10
45 -> 9/10
50 -> 10/10
So that's values such as C or D. They range between 0-50 and should be put into a 0-10 format for readability. There are a fair few of these values too.
Also there are conversions like "GoodieBaddie" which vary from 0 to 10. Which we wish to convert to something like:
0-3 -> Bad(x)
4-6 -> Neutral(x)
7-10 -> Good(x)
Where (x) is the original value.
Am I even using the right tool for the job here or is it borderline? I figured XLST would be a good choice to enable other contributors to not have to rely on the devs to make changes to the formatting/layout (as xlst is easier to edit then say C# or Python).
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:attitudes>
<a val="1">ANNOYED</a>
<a val="2">CAUTIOUS</a>
<a val="3">PLEASED</a>
</my:attitudes>
<xsl:variable name="vAttitudes" select="document('')/*/my:attitudes/*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(., 'ATTITUDE_')]/text()">
<xsl:variable name="vVal" select=
"$vAttitudes[. = substring-after(current(), '_')]/#val"/>
<xsl:value-of select="concat('ATTITUDE_', $vAttitudes[#val = $vVal+1])"/>
</xsl:template>
<xsl:template match="*[floor(.) = .]/text()">
<xsl:value-of select="concat(round(. div 5), '/10')"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<data>
<a>ATTITUDE_ANNOYED</a>
<b>ATTITUDE_CAUTIOUS</b>
<c>25</c>
<d>30</d>
</data>
</root>
produces the wanted, correct result:
<root>
<data>
<a>ATTITUDE_CAUTIOUS</a>
<b>ATTITUDE_PLEASED</b>
<c>5/10</c>
<d>6/10</d>
</data>
</root>
I'm working with xslt for the first time. I have 2.0, but that's about the only advantage I have access to with the c# transform library we have. I'm trying to count a number of child nodes in the XML document which contain a date more than 12 years ago and have a certain type attribute.
Sample xml structure:
<xml version=\"1.0\" encoding=\"utf-8\"?>
<... />
<Dependents>
<Dependent><DOB>1964-04-01</DOB><DependentType>Spouse</DependentType></Dependent>
<Dependent><DOB>2000-01-01</DOB><DependentType>Child</DependentType></Dependent>
<Dependent><DOB>2012-01-01</DOB><DependentType>Child</DependentType></Dependent>
</Dependents>
<... />
where <... /> signifies some extra unrelated stuff.
So essentially, I want the number of children younger than 12 years old. (I have the count of dependenttype = child of all ages working, it's just the under 12 that's giving me trouble). The approach that was suggested to me was to construct a variable that stands for 12 years ago from today and use that as a basis for comparison in the count() function. That sounds reasonable, but I'm stuck constructing the date without the use of 3rd party libraries (e.g. exslt) that are so often linked in questions like this for the easy, handy-dandy answers.
The xslt I've gotten so far for this is:
<xsl:variable name="today" select="current-dateTime()" as="xs:dateTime" />
<xsl:variable name="twelveyearsago" select="xs:dateTime(concat(year-from-dateTime($today) - 12, '-', month-from-dateTime($today), '-', day-from-dateTime($today)))" />
<xsl:text>12yearsago=</xsl:text><xsl:value-of select="$twelveyearsago" />
And it's not working because the month-from-dateTime (and presumable day-from-dateTime) don't add leading zeros. For today, March 21 2012 I'm getting back: Saxon.Api.DynamicError : Invalid dateTime value "2000-3-21" (Month must be two digits) (The W3Schools xpath function reference implies that they should, but they don't.)
What I would like to output is:
<xsl:text>&numberofchildren=</xsl:text><xsl:value-of select="count(//InsuranceRequest/HealthInsurance/Dependents/Dependent/DependentType[text() = 'Child'])" />
<xsl:text>&childrenunder12=</xsl:text><xsl:value-of select="children under twelve" />
The more I pound my head against this, the more I feel like there's a simpler approach that I'm just not seeing.
Edit: I cleaned up the xslt syntax so it's valid and not a doubly-quoted c# string.
You can simply substract a duration of 12 years as in <xsl:variable name="twelveyearsago" select="$today - xs:yearMonthDuration('P12Y')"/>, then use e.g. //Dependent[DependentType = 'Child' and xs:date(DOB) >= $twelveyearsago].
[edit]
Here is a template that compiles and executes fine for with Saxon 9.4:
<xsl:template match="/">
<xsl:variable name="today" select="current-date()"/>
<xsl:variable name="twelve-years-ago" select="$today - xs:yearMonthDuration('P12Y')"/>
<xsl:value-of select="count(//Dependent[DependentType = 'Child' and xs:date(DOB) >= $twelve-years-ago])"/>
</xsl:template>
Hope someone can help. I am trying to compare 2 dates inside an XML file and using a XSLT to do some calculation:
For example I have 2 dates in XML: 2011-05-23 and 2011-04-29. I want to do calculation inside XSLT like below:
('2011-05-23'-'2011-04-29')*30 = 24*30= 720
Can anyone shed any light?
An XSLT 2.0 solution
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="/">
<xsl:value-of select="days-from-duration(
xs:date('2011-05-23')
- xs:date(xs:date('2011-04-29'))
)*30"/>
</xsl:template>
</xsl:stylesheet>
Yields: 720
xs:date() function evaluates the dates, which can be used to perform date operations
subtracting the second date from the first yields the xdt:dayTimeDuration P24D (24 days)
days-from-duration() extracts the days component from the xdt:dayTimeDuration (24)
then you can use that number to perform normal arethmatic (e.g. 24*30=720)
It might be worth looking at the EXSLT - date:difference solution. I believe that should do what you want, and there's even a straight XSLT implementation available.
Be aware though that the returned value is in duration format as specified in the XML Schema Part 2: Datatypes Second Edition, so it's likely you will need to process the result to derive the unit you wish to use in calculation (for instance in your example above you're expecting a result detailing the number of days difference - so you would need to pull out the relevant unit you want to work with, the result from date:difference in that case would most likely be "P24D").
Here's two templates I sometimes use for date calculations:
<xsl:template name="calcseconds">
<xsl:param name="date" />
<xsl:value-of select="(((substring($date,1,4) - 1970) * 365)+floor((substring($date,1,4) - 1970) div 4)+substring('000,031,059,090,120,151,181,212,243,273,304,334,365',substring($date,6,2)*4-3,3)+(substring($date,9,2)-1)+(1-floor(((substring($date,1,4) mod 4) + 2) div 3))*floor((substring($date,6,2)+17) div 20))*86400+(substring($date,12,2)*3600)+(substring($date,15,2)*60)+substring($date,18,2)" />
</xsl:template>
<xsl:template name="calcdays">
<xsl:param name="date" />
<xsl:value-of select="(((substring($date,1,4) - 1970) * 365)+floor((substring($date,1,4) - 1970) div 4)+substring('000,031,059,090,120,151,181,212,243,273,304,334,365',substring($date,6,2)*4-3,3)+(substring($date,9,2)-1)+(1-floor(((substring($date,1,4) mod 4) + 2) div 3))*floor((substring($date,6,2)+17) div 20))" />
</xsl:template>
They're a bit of a mouthful, but they'll calculate the number of seconds/days since midnight 1st January 1970 as an integer, which you can then do straight arithmetic on. They rely on the date format being yyyy-mm-dd hh:mm:ss, but manipulation of the parameters of the substring calls should allow you to process dates in any format you need.