I have to solve something with XSLT and am at a loss. I think I need the string-length function, some chose tests, and substring, but I don’t know. The problem is relatively simple.
My xml looks like the sample below. However, I have used YYYY, MM, and DD to represent numbers in the dates.
<date normal=”YYYMMDD”> Month, DD, YYYY</date>
<date normal=”YYYY/YYYY”> YYYY-YYYY</date>
<date normal=”YYYYMM”> Month, YYYY</date>
<date normal=”YYYYMM>MM-YYYY</date>
<name normal=”Smith, John”> John Smith </name>
I need to print all the elements as they are, except for JUST the two elements that have attributes normal=”YYYYMM”. They need to be printed but with attributes in the form normal=YYYY-MM
I cannot rely on the material in the element as it tends to be in a variety of different formats as it is free text.
I keep trying to use string-length function to identify attribute values with 6 characters in the element date. But then I can’t figure out how to split the string in the output with the hyphen. I am guessing it uses one of the substring functions, but I can’t get everything to work together.
Thanks for any advice you can give,
Christine
Something like this?:
<xsl:choose>
<xsl:when text="string-length(#normal) = 6 and number(#normal) = number(#normal)">
<xsl:value-of select="concat(substring(#normal, 1, 4), '-', substring(#normal, 5, 2))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#normal" />
</xsl:otherwise>
</xsl:choose>
The number(#normal) = number(#normal) check ensures that #normal is a number, since it looks like you also have some non-date values in the normal attribute. Is there any risk that it might be a 6-digit non-date number?
This complete and short transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#normal[string-length()=6]">
<xsl:attribute name="normal">
<xsl:value-of select="concat(substring(.,1,4),'-',substring(.,5))"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document (the provided fragment wrapped into a single top element):
<t>
<date normal="YYYMMDD"> Month, DD, YYYY</date>
<date normal="YYYY/YYYY"> YYYY-YYYY</date>
<date normal="YYYYMM"> Month, YYYY</date>
<date normal="YYYYMM">MM-YYYY</date>
<name normal="Smith, John"> John Smith </name>
</t>
produces the wanted, correct result:
<t>
<date normal="YYYMMDD"> Month, DD, YYYY</date>
<date normal="YYYY/YYYY"> YYYY-YYYY</date>
<date normal="YYYY-MM"> Month, YYYY</date>
<date normal="YYYY-MM">MM-YYYY</date>
<name normal="Smith, John"> John Smith </name>
</t>
Related
In Excel while Calculating =SIN(PI()) formula it returns 1.22515E-16.If the PI() Value(3.14159265358979) is directly given like =SIN(3.14159265358979), it returns 3.23114E-15.
Please anyone can share your opinion about how the excel calculates differently, when 'PI' and 3.14159265358979 are passed as parameter.
Let's have the following example:
A2 is formula =PI().
A3 is value 3.14159265358979.
A5 is value copied from A2 and then paste-special: Values only.
Formula in column B is =SIN(A2) ... =SIN(A5).
So what is happening here?
While Microsoft justifies the truncating values to 15 digits with using double floating point precision according IEEE 754, this is not the whole truth. According IEEE 754 the possible count of decimal digits is not exactly 15 but 15.95 in average. So there are more digits possible in some cases. And if so, Excel stores up to 17 digits in its files although it shows only 15 digits in its sheet views and also only 15 digits can be input in its sheet views.
So =PI() will result in 3.1415926535897931 exactly and this value will also be stored. But manual input can only be 3.14159265358979. But if you copy/paste-special:Values the result of =PI(), then also 3.1415926535897931 will be stored although only 3.14159265358979 is shown.
Since *.xlsx files are simply ZIP archives, we can unzip them and look at /xl/worksheets/sheet1.xml. There we will find:
<row r="2" spans="1:2" x14ac:dyDescent="0.25">
<c r="A2" s="1">
<f>PI()</f>
<v>3.1415926535897931</v>
</c>
<c r="B2">
<f>SIN(A2)</f>
<v>1.22514845490862E-16</v>
</c>
</row>
<row r="3" spans="1:2" x14ac:dyDescent="0.25">
<c r="A3" s="1">
<v>3.14159265358979</v>
</c>
<c r="B3">
<f>SIN(A3)</f>
<v>3.2311393144413003E-15</v>
</c>
</row>
<row r="5" spans="1:2" x14ac:dyDescent="0.25">
<c r="A5" s="1">
<v>3.1415926535897931</v>
</c>
<c r="B5">
<f>SIN(A5)</f>
<v>1.22514845490862E-16</v>
</c>
</row>
q.e.d.
The reason you are seeing this is because of a rounding error.
Sin(PI()) is technically 0, as detailed in the Sin function documentation. However, excel returns 1.22515E-16 or 0.0000000000000001225148455
(i.e. approximately 0)
3.14159265358979 is a approximation of PI(), so it returns a different number that it also approximately 0. If you try 3.1415926535897, 3.141592653589 etc, you will get a different number each time.
This is likely related to working with floats, but I don't know enough about Excel and how it stores data to elaborate.
The SIN() function accepts the parameter in radians.
To convert an angle to radians, the value must be multiplied by PI()/180.
If you use =SIN(PI()), the PI is considered as a radian which is equal to RADIANS(180). Both =SIN(PI()) and =SIN(RADIANS(180)) returns the same result 0.
=SIN(3.14159265358979) is not actually equal to =SIN(PI()) because the PI in this context is different. And hence the different result.
The bottom line is to always use radians as a parameter for trigonometric functions.
I have this XML structure.
<Organisation>
<Employee type="gorilla">
<Publication>
The Hills and the Sunrise, 1-2013-05, $94,000
</Publication>
<Publication>
Sunny and Rainy on the same day, 1-2013-05, $584,932
</Publication>
</Employee>
<Employee type="gorilla">
<Publication>
The Hills and the Sunrise, 1-2013-05, $94,000
</Publication>
<Publication>
Sunny and Rainy on the same day, 1-2013-05, $584,932
</Publication>
</Employee>
<Employee type="pig">
<pigpen>
</pigpen>
</Employee>
</Organisation>
I would like to know how I can select only the dollar amount at the end of every Publication where an employe type = gorilla, and add these values together to give the total publication income. I would also like to use this total to calculate the average income per gorilla employee.
How could I go about doing this? I'm having trouble finding a function to select just the dollar amounts.
If there isn't a method to do this in XSLT 1, would it be considered good coding form to add more nodes to store the dollar amounts separately?
e.g.
<Publication>
<Description>The Hills and the Sunrise</Description>
<Amount>$94,000</Amount>
</Publication>
I am in the process of building a "dashboard" where I am using DVWP's and XSLT to show the client things such as total count of tasks, how many open, how many closed etc. similar to this article
My issue is that I have a multi-value lookup column for which I need to get the count of the values, but I am not able to generate any results with what I have tried.
Any suggestions or recommendations on how to accomplish would be great.
So to add to the above as an update:
I am not exactly certain the best approach on how to achieve the desired results. Essentially I have a multi-value lookup column that currently has 20 values. The client has the ability to add new values when needed. So what I am attempting to do is to get a totals type count of the values they have selected for each record.
So let's say for example the lookup colum has five (5) values:
Value 1
Value 2
Value 3
Value 4
Value 5
In the newform.aspx they have the ability to select multiple values (so the could select value 3 and value 5; or value 2, value 4, and value 5 etc etc). In the list view it of course shows the selections as it should. What I am attempting to do is to get a total count of those values.
For example the output would look something like:
Value 1 : 5
Value 2 : 1
Value 3 : 2
Value 4 : 3
Value 5 : 6
Value 3 & 5 : 4
Value 2,4, & 5: 3
I am not certain about the XSLT to develop such a thing as I have not had to do this with such a complex Lookup Column before. Normally I would do someting like below, but this only gets me the basics, and since the values can be combined I am not certain how to approach:
<xsl:template name="dvt_1.body">
<xsl:param name="Rows"/>
<xsl:variable name="total1" select="count(/dsQueryResponse/Rows/Row/#MyLookupCol.[contains(.,'1;#Value1')])"></xsl:variable>
<xsl:call-template name="cs3_totalRow">
<xsl:with-param name="cs3_RowName1">
Value 1
</xsl:with-param>
<xsl:with-param name="cs3_RowValue1">
<xsl:value-of select="$total1"/>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="totalsRow">
<xsl:param name="RowName1"></xsl:param>
<xsl:param name="RowValue1"></xsl:param>
<table>
<tr>
<td>
<xsl:value-of select="$cs3_RowName1"/>:
</td>
<td>
<xsl:value-of select="$cs3_RowValue1"/>
</td>
</tr>
</table>
OK; figured it out. You will need to use MUENCHIAN METHOD which utilizes keys in order to generate something of a "distinct group by" list and then use count in your expression and count the keys.
References used are here and here
See the code below for details:
<!--GROUPING USING THE MUENCHIAN METHOD-->
<!--Add a key as shown below. This is important! Will not "group by" without it-->
<xsl:key name="YourKeyNameHere" match="Row" use="#YourColumnName"/>
<xsl:template match="/">
<!--Get your column values look you normally would-->
<xsl:variable name="cbs_Rows" select="/dsQueryResponse/Rows/Row/#YourColumnName"/>
<table border="0" width="100%" cellpadding="2" cellspacing="0">
<tr valign="top">
<th class="ms-vh" nowrap="nowrap">TheValueName</th>
<th class="ms-vh" nowrap="nowrap">ValueTotals</th>
</tr>
<!--This gets the distinct strings for you.-->
<xsl:for-each select="//Row[generate-id() = generate-id(key('YourKeyName', #YourColumnName)[1])]">
<xsl:sort select="#YourColumnName"/>
<xsl:for-each select="key('YourKeyName', #YourColumnName)">
<xsl:call-template name="Rows.RowView" />
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
<!--then build your row view-->
<xsl:template name="Rows.RowView">
<xsl:variable name="SortValue" select="ddwrt:NameChanged(string(#YourColumnName), 0)"/>
<xsl:if test="string-length($SortValue) > 0">
<tr id="group0{generate-id()}">
<td>
<xsl:value-of select="#YourColumnName"/>
</td>
<td>
<xsl:value-of select="count(key('YourKeyName', #YourColumnName))"></xsl:value-of>
</td>
</tr>
</xsl:if>
</xsl:template>
I am getting an extra empty row between data when I am importing it from the database and formatting the report in Excel sheet.
EDIT (clarification from a comment): The output in Excel shows an extra blank row between records and and extra blank column between fields.
Add net.sf.jasperreports.export.xls.remove.empty.space.between.columns and net.sf.jasperreports.export.xls.remove.empty.space.between.rows properties to report template.
net.sf.jasperreports.export.xls.remove.empty.space.between.columns - Specifies whether the empty spacer columns should be removed or not.
net.sf.jasperreports.export.xls.remove.empty.space.between.rows - Specifies whether the empty spacer rows should be removed or not.
The sample:
<jasperReport ...>
<property name="ireport.zoom" value="1.0"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="0"/>
<property name="net.sf.jasperreports.export.xls.remove.empty.space.between.columns" value="true"/>
<property name="net.sf.jasperreports.export.xls.remove.empty.space.between.rows" value="true"/>
The information about configuration properties is here.
You can set isRemoveLineWhenBlank and isBlankWhenNull for textField element for hiding blank row.
The sample how to remove the whole line if the current textField is empty:
<textField isBlankWhenNull="true">
<reportElement x="0" y="0" width="100" height="20" isRemoveLineWhenBlank="true"/>
<textElement/>
<textFieldExpression><![CDATA[$F{field}]]></textFieldExpression>
</textField>
Another assumption is to change the height of all textField (or/and staticText) elements in the Band.
In case this design:
you will have a space between any two rows.
In case this design (textField height is equal to the Band's height):
the each line will be exactly under the other.
Every thing that Alex K states in his Dec 2 '11 answer is correct. But a few other settings may be helpful. These settings help when the text of the report stretches the detail band.
On every field in the detail band set:
positionType="Float"
stretchType="RelativeToTallestObject"
Example:
<detail>
<band height="20" splitType="Prevent">
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
<reportElement positionType="Float" stretchType="RelativeToTallestObject" mode="Transparent" x="372" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{your column name}]]></textFieldExpression>
</textField>
This will force the all fields to be one height. The float setting tells the field to minimize the distance between the previous and next row. The RelativeToTallestObject setting tells all fields in the band to be the same height as the tallest field. These two settings help eliminate 'empty space' which shows up as unwanted cells in Excel.
i have a sharepoint list column which has number datatype ..whenever the user sorts them ascending or descending i should get it as they were..but xslt sorting allows either ascending or descending..how can i make it flexible?..could anyone please help me with this
you can use conditional formating
<xsl:choose>
<xsl:when test="$sortorder='Asc'>
<xsl:call-template name="asctemplate" />
</xsl:when>
<xsl:when test="$sortorder='Desc'>
<xsl:call-template name="desctemplate" />
</xsl:when>
</xsl:choose>