How to show all XSL elements? - asp.net

The XML file contains Accounts and a list of Account (contains ID and AccountDescription).
In the below example, there are 2 Account.
<?xml version="1.0"?>
<Accounts>
<Account>
<ID>5</ID>
<AccountDescription>Account Description 5</AccountDescription>
</Account>
<Account>
<ID>8</ID>
<AccountDescription>Account Description 8</AccountDescription>
</Account>
</Accounts>
When using the below XSL, it creates a PDF file with 2 pages, and each page has the header ID and AccountDescription, but there is no data/content underneath it, like this:
On page 1:
ID AccountDescription
On page 2:
ID AccountDescription
I would like to show the data like this:
ID AccountDescription
5 Account Description 5
8 Account Description 8
How can I do that ? Thank you.
This is my current XSL:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="Accounts">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master
master-name="main"
margin-top="0px"
margin-bottom="0px"
margin-left="18px"
margin-right="18px">
<fo:region-body margin-top="0.75in" margin-bottom="2in" margin-left="18px" margin-right="18px"/>
<fo:region-before extent="0.75in"/>
<fo:region-after extent="1.5in"/>
<fo:region-end extent="75px"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:apply-templates select="Account"/>
</fo:root>
</xsl:template>
<xsl:template match="Account">
<fo:page-sequence master-reference="main">
<fo:flow flow-name="xsl-region-body">
<fo:table font-size="10pt">
<fo:table-column column-width="15mm"/>
<fo:table-column column-width="55mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="ID"/></fo:block>
</fo:table-cell>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="AccountDescription"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</xsl:template>
</xsl:stylesheet>

How can I show all data in the same page ?
You need to use only one fo:page-sequence. Move it from the Account template up into the Accounts template.
Updated XSLT
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="Accounts">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master
master-name="main"
margin-top="0px"
margin-bottom="0px"
margin-left="18px"
margin-right="18px">
<fo:region-body margin-top="0.75in" margin-bottom="2in" margin-left="18px" margin-right="18px"/>
<fo:region-before extent="0.75in"/>
<fo:region-after extent="1.5in"/>
<fo:region-end extent="75px"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="main">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="Account"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="Account">
<fo:table font-size="10pt">
<fo:table-column column-width="15mm"/>
<fo:table-column column-width="55mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="ID"/></fo:block>
</fo:table-cell>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="AccountDescription"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>

Related

Numbering tables where multiple instances count as one table XSLT 3.0

Given this XML:
<preliminaryRqmts>
<!-- Table 1 -->
<reqCondGroup>
<reqCondNoRef>
<reqCond>Lorem ipsum</reqCond>
</reqCondNoRef>
</reqCondGroup>
<!-- Table 2 -->
<reqPersons>
<person man="A">
<personCategory personCategoryCode="Chemical technician"/>
<personSkill skillLevelCode="sk02"/>
<trade>Cleaner</trade>
<estimatedTime unitOfMeasure="h">1,0</estimatedTime>
</person>
</reqPersons>
<reqPersons>
<person man="B">
<personCategory personCategoryCode="Operator"/>
<personSkill skillLevelCode="sk02"/>
<trade>Painter</trade>
<estimatedTime unitOfMeasure="h">1,0</estimatedTime>
</person>
</reqPersons>
<reqPersons>
<person man="B">
<personCategory personCategoryCode="Operator"/>
<personSkill skillLevelCode="sk03"/>
<trade>Rider</trade>
<estimatedTime unitOfMeasure="h">0,8</estimatedTime>
</person>
</reqPersons>
<!-- Table 3 -->
<reqSafety>
<noSafety/>
</reqSafety>
</preliminaryRqmts>
<taskDefinition>
<task>
<taskDescr>
<simplePara>Lorem ipsum</simplePara>
</taskDescr>
</task>
<preliminaryRqmts>
<!-- Table 4 -->
<reqCondGroup>
<noConds/>
</reqCondGroup>
<!-- Table 5 -->
<reqPersons>
<person man="A">
<personCategory personCategoryCode="Basic user"/>
<trade>Operator</trade>
<estimatedTime unitOfMeasure="h">0,3</estimatedTime>
</person>
</reqPersons>
<!-- Table 6 -->
<reqSpares>
<noSpares/>
</reqSpares>
</preliminaryRqmts>
</taskDefinition>
I have to include the Table number when outputting the table title. <reqPersons> may have multiple siblings but they are counted as one table. So in the XML provided, the first three reqPersons are counted as one table, Table 2. reqPersons is not a required element so there could be <preliminaryRqmts> without any <reqPersons>.
I am having trouble getting the correct table numbering for reqPersons when there is more than one preliminaryRqmts with a reqPersons. Originally I had <xsl:value-of select="if(preceding::reqPersons) then 1 else 0"/>. This fails when there are multiple preliminaryRqmts/reqPersons.
Here are the templates for the table numbering and reqPersons. Only the first reqPersons gets a title and table number. Any following-siblings::reqPersons are ignored in the table count. I need help with fixing <xsl:variable name="countPer" select="count(ancestor-or-self::preliminaryRqmts/reqPersons[1])"/>, the rest of the numbering is working properly.
<xsl:template match="reqPersons[1]">
<fo:block>
<xsl:text>Table </xsl:text>
<xsl:call-template name="number-tables"/>
<xsl:text>  Required persons</xsl:text>
</fo:block>
<fo:table>
<xsl:call-template name="reqPersonTableBody"/>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="reqPersons">
<fo:block>
<fo:table>
<xsl:call-template name="reqPersonTableBody"/>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template name="reqPersonTableBody">
<fo:table-column column-number="1" column-width="33%"/>
<fo:table-column column-number="2" column-width="33%"/>
<fo:table-column column-number="3" column-width="33%"/>
<fo:table-header>
<fo:table-row>
<fo:table-cell>
<fo:block>Person</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Category</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Skill level</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="personnel | person"/>
</fo:table-body>
</xsl:template>
<xsl:template name="number-tables">
<xsl:variable name="countreqCondTables" select="count(preceding::reqCondGroup|preceding::reqSupportEquips|preceding::reqSupplies|preceding::reqSpares|preceding::reqTechInfoGroup)"/>
<xsl:variable name="countPer" select="count(ancestor-or-self::preliminaryRqmts/reqPersons[1])"/>
<xsl:variable name="countSelfPer" select="count(ancestor-or-self::reqPersons[1])"/>
<xsl:variable name="countSelf" select="count(ancestor-or-self::table|ancestor-or-self::reqCondGroup|ancestor-or-self::reqSupportEquips|ancestor-or-self::reqSupplies|
ancestor-or-self::reqSpares|ancestor-or-self::reqTechInfoGroup)"/>
<xsl:value-of select="$countPer+$countSelf+$countSelfPer+$countreqCondTables"/>
</xsl:template>
I would check whether you can use xsl:number count="some pattern matching the elements you want to count" level="any" e.g. in XSLT 3
<xsl:param name="table-count-pattern" static="yes" as="xs:string" select="'preliminaryRqmts/reqCondGroup | preliminaryRqmts/reqPersons[1] | preliminaryRqmts/reqSafety | preliminaryRqmts/reqSpares'"/>
<xsl:template _match="{$table-count-pattern}">
<xsl:comment>computed table <xsl:number _count="{$table-count-pattern}" level="any"/></xsl:comment>
<xsl:next-match/>
</xsl:template>
seems to give the numbers you have in your comments output in another comment. Of course, you don't want to output a comment, you want to output that number in your fo:block but you can obviously adapt the above suggestion easily. If needed, if you have lots of different templates for all the elements that need to output that count, put the above template in a mode with e.g. mode="count", and in your other templates, where you need to number, use e.g. <xsl:apply-templates select="." mode="count"/>. You will probably want to remove the xsl:next-match in that case.

access multiple elements of same XML at different depths to convert to R tibble

I have a fairly deep xml file of travel data that I've anonymized here. I would like to pull out the coupon statuses for multiple segments and attach them to the itinerary id. I'm having a very difficult time using the xml2 package and I think the reason why is that some of my XML data terminates with text and some terminate with attributes. I've tried to convert the xml to a list with as_list(). I've also tried to start with xml_find_all() but get a nodeset of 0 regardless of the node I search for (Ticketing or Coupons should work, for example). Below is the data:
<?xml version="1.0" encoding="UTF-8"?>
<eTicketCouponRS xmlns="http://webse" xmlns:ns4="http://s" xmlns:stl="http://se" Version="2.0.0">
<stl:ApplicationResults status="Complete">
<stl:Success timeStamp="2021-06-16T11:39:52-05:00" />
</stl:ApplicationResults>
<TicketingInfos>
<TicketingInfo>
<Ticketing AgencyCity="DCA" AgentWorkArea="A" IATA_Number="0952" IssuingAgent="A" PrimeHostID="1S" PseudoCityCode="5SE0" TransactionDateTime="2021-06-16T11:39">
<CouponData InformationSource="S" IssueDate="2021-03-29" NumBooklets="1" TicketMedia="E" TicketMode="63">
<AirItineraryPricingInfo>
<FareCalculation>
<Text>SAN AA X/E/DFW AA TYO M0.00NUC0.00END ROE1.00 XFSAN4.5DFW4.5</Text>
</FareCalculation>
<ItinTotalFare>
<BaseFare Amount="0.00" CurrencyCode="USD" />
<Taxes>
<Tax Amount="19.10" TaxCode="US" />
<Tax Amount="5.60" TaxCode="AY" />
<Tax Amount="9.00" TaxCode="XF" />
</Taxes>
<TotalFare Amount=".70" CurrencyCode="USD" />
</ItinTotalFare>
<PassengerTypeQuantity Code="GV1" />
</AirItineraryPricingInfo>
<Coupons>
<Coupon CodedStatus="OK" Number="1" StatusCode="RFND">
<FlightSegment DepartureDateTime="2021-08-13T06:15" FlightNumber="2535" RPH="1" ResBookDesigCode="V">
<DestinationLocation LocationCode="DFW" />
<FareBasis Code="VCA" />
<MarketingAirline Code="AA" FlightNumber="2535" />
<OperatingAirline Code="AA" />
<OriginLocation LocationCode="SAN" />
</FlightSegment>
</Coupon>
<Coupon CodedStatus="OK" Number="2" StatusCode="RFND">
<FlightSegment ConnectionInd="X" DepartureDateTime="2021-08-13T12:20" FlightNumber="175" RPH="2" ResBookDesigCode="V">
<DestinationLocation LocationCode="HND" />
<FareBasis Code="VCA" />
<MarketingAirline Code="AA" FlightNumber="175" />
<OperatingAirline Code="AA" />
<OriginLocation LocationCode="DFW" />
<FareTypeClass>PG</FareTypeClass>
<FareTypeRule>OW-GO</FareTypeRule>
</FlightSegment>
</Coupon>
</Coupons>
<CustomerInfo>
<Customer>
<Invoice Number="126" />
<Payment ApprovalID="03" RPH="1" ReferenceNumber="XXXXXXXXXXXX" Type="CC">
<CC_Info>
<PaymentCard Code="VI" ExpirationDate="XX-XX" />
</CC_Info>
</Payment>
<PersonName NameReference="PCS" PassengerType="GV1">
<GivenName>VER</GivenName>
<Surname>DE</Surname>
</PersonName>
</Customer>
</CustomerInfo>
<ItineraryRef CustomerIdentifier="R5" ID="EXAMPLE" />
</CouponData>
</Ticketing>
</TicketingInfo>
</TicketingInfos>
</eTicketCouponRS>
I have about 100 of these each to load separately and pull out a small table consisting of the following columns:
SuccTimeStamp TransacTimeStamp ItineraryID CouponNumber StatusCode Origin Destination OperatingAirline FlightNumber.
You can see that each of these elements are found at different depths of the xml and every travel itinerary has a different number of coupons, anywhere from 1-10. I also found a helpful post here from hrbrmstr helping out someone from 2018, but I can't get a similar solution to "see" my nodes and I'm not sure if it's my code or my xml data.
Any help is appreciated!
For nested XML files which you need to flatten for end use needs such as R, consider XSLT, the special-purpose language designed to transform XML files. You can run XSLT 1.0 scripts in R using the xslt package (sister to xml2). Alternatively, you can use a dedicated XSLT processor and have R call the external program with system(). Like SQL, XSLT is an industry, portable language not limited to R.
Within XSLT, since your granularity is coupon, you can extract from <Coupon> level and use the ancestor:: XPath axe to retrieve higher up level information. Due to the default namespace needs, the long-windeed <xsl:element> is used. IATA_Number is assumed to be ItineraryID.
XSLT (save as .xsl file, a special .xml file)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="http://webse"
xmlns:stl="http://se">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/w:eTicketCouponRS">
<xsl:copy>
<xsl:apply-templates select="descendant::w:Coupon"/>
</xsl:copy>
</xsl:template>
<xsl:template match="w:Coupon">
<xsl:copy>
<xsl:element name="SuccTimeStamp" namespace="http://webse">
<xsl:value-of select="ancestor::w:eTicketCouponRS/stl:ApplicationResults/stl:Success/#timeStamp"/>
</xsl:element>
<xsl:element name="TransacTimeStamp" namespace="http://webse">
<xsl:value-of select="ancestor::w:Ticketing/#TransactionDateTime"/>
</xsl:element>
<xsl:element name="ItineraryID" namespace="http://webse">
<xsl:value-of select="ancestor::w:Ticketing/#IATA_Number"/>
</xsl:element>
<xsl:element name="CouponNumber" namespace="http://webse">
<xsl:value-of select="#Number"/>
</xsl:element>
<xsl:element name="StatusCode" namespace="http://webse">
<xsl:value-of select="#CodedStatus"/>
</xsl:element>
<xsl:element name="Origin" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:OriginLocation/#LocationCode"/>
</xsl:element>
<xsl:element name="Destination" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:DestinationLocation/#LocationCode"/>
</xsl:element>
<xsl:element name="OperatingAirline" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:OperatingAirline/#Code"/>
</xsl:element>
<xsl:element name="FlightNumber" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/#FlightNumber"/>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Online Demo
R
library(xml2)
library(xslt)
# LOAD XML AND XSLT
doc <- read_xml("/path/to/Input.xml")
style <- read_xml("/path/to/Style.xsl", package = "xslt")
# RUN TRANSFORMATION AND SEE OUTPUT
flat_xml <- xml_xslt(doc, style)
cat(as.character(flat_xml))
# RETRIEVE data NODES
nmsp <- c(w = "http://webse")
recs <- xml2::xml_find_all(flat_xml, "//w:Coupon", ns=nmsp)
# BIND EACH CHILD TEXT AND NAME
df_list <- lapply(recs, function(r) {
vals <- xml2::xml_children(r)
data.frame(rbind(setNames(c(xml2::xml_text(vals)),
c(xml2::xml_name(vals)))))
})
# COMBINE ALL DFS
final_df <- do.call(rbind.data.frame, df_list)
rm(recs, df_list)
final_df
# SuccTimeStamp TransacTimeStamp ItineraryID CouponNumber StatusCode Origin Destination OperatingAirline FlightNumber
# 1 2021-06-16T11:39:52-05:00 2021-06-16T11:39 0952 1 OK SAN DFW AA 2535
# 2 2021-06-16T11:39:52-05:00 2021-06-16T11:39 0952 2 OK DFW HND AA 175
Above runs for a single XML. For 100 separate files, wrap above in a user-defined method and run lapply for a list of XML dataframes for master concatenation at very end. Load XSLT once outside loop since it does not change, assuming XML files retain same structure.
style <- read_xml("/path/to/Style.xsl", package = "xslt")
xml_to_df <- function(xml_file) { ... }
xml_dfs <- lapply(list_of_xml_files, xml_to_df)
master_df <- do.call(rbind.data.frame, xml_dfs)
Thanks Parfait! I was able to modify the template xsl that you provided. The xsl sheet seems to "parse" everything nicely! After I got it "flattened", all I simply had to do was as_list(), as_tibble() and unnest() a couple of times and then it was a data frame.
Thanks!

processing css stylesheet with xml document

I am new to XML (a couple of days now...)and everything is going good, however, I can't seem to get the xml processed with css style
here is my perl...
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
my $ifile="elementarray.csv";
my $ofile="elementarray.xml";
open my $fh, "<", $ifile or die $ifile.": $!";
open my $out, "> ".$ofile or die "Cannot write ".$ofile.": $!";
print $out <<EOT;
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="elementarray.xsl"?>
<?xml-stylesheet href="elementarray.css" title="Default style"?>
<EMAILCOMMENTS>
EOT
# First record contains list of fieldnames
#my $fields = $csv->getline($fh);
#print #$fields;
while (my $row = $csv->getline($fh)) {
last unless $row && #$row;
# Encode "<" characters as "<" and "&" as "&" in all fields
foreach (#$row) {
s/&/&/g;
s/</</g;
}
# Create hash of fields using hash slice
my %row;
#row{"Subject","Body","From: (Name)","From: (Address)","To: (Name)","To:(Address)","Date","Time"} = #$row;
print $out <<EOT;
<EMAIL>
<HEADER>
<ORIGNAME>$row{"From: (Name)"}</ORIGNAME>
<ORIGADDRESS>$row{"From: (Address)"}</ORIGADDRESS>
<DESTNAME>$row{"To: (Name)"}</DESTNAME>
<DESTADDRESS>$row{"To: (Address)"}</DESTADDRESS>
<SUBJECT>$row{"Subject"}</SUBJECT>
</HEADER>
<BODY>$row{"Body"}</BODY>
<DATE id="date">$row{"Date"}</DATE>
<TIME id="time">$row{"Time"}</TIME>
</EMAIL>
EOT
}
print $out "</EMAILCOMMENTS>\n";
$csv->eof or $csv->error_diag;
close $fh or die $ifile.": $!";
close $out or die $ofile.": $!";
Here is my xsl...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="html"/>
<xsl:template match="/"><!-- a 'pattern', / matches the root node -->
<html>
<head>
<title>E-mail</title>
</head>
<body>
<xsl:apply-templates/><!-- an instruction -->
</body>
</html>
</xsl:template>
<xsl:template match="HEADER">
<span STYLE="color:red; font-weight:bold; font-style:italic">
<xsl:value-of select="SUBJECT"/>
</span>
From: <xsl:call-template name="formatEmail">
<xsl:with-param name="address" select="ORIGADDRESS"/>
</xsl:call-template>
To: <xsl:call-template name="formatEmail">
<xsl:with-param name="address" select="DESTADDRESS"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="EMAIL">
<xsl:apply-templates select="HEADER"/>
<pre>
<xsl:value-of select="BODY"/>
</pre>
<div>
<span>
<xsl:attribute name="id"><xsl:value-of select="date"/></xsl:attribute>
<!-- --><xsl:value-of select="DATE"/><!-- --></span>
<span>
<xsl:attribute name="id"><xsl:value-of select="time"/></xsl:attribute>
<!-- --><xsl:value-of select="TIME"/><!-- --></span>
</div>
<br />
</xsl:template>
<xsl:template name="formatEmail">
<xsl:param name="address"/>
<a>
<xsl:attribute name="href"><xsl:value-of select="concat('mailto:',$address)"/></xsl:attribute>
<xsl:value-of select="$address"/>
</a>
</xsl:template>
</xsl:stylesheet>
here is my xml (1 record)...
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="elementarray.xsl"?>
<?xml-stylesheet href="elementarray.css" title="Default style"?>
<EMAILCOMMENTS>
<EMAIL>
<HEADER>
<ORIGNAME>William Holt</ORIGNAME>
<ORIGADDRESS><x#gmail.com></ORIGADDRESS>
<DESTNAME>X</DESTNAME>
<DESTADDRESS>bill#elementarray.com</DESTADDRESS>
<SUBJECT>welcome to the neighborhood</SUBJECT>
</HEADER>
<BODY>just thought i'd say hello</BODY>
<DATE id="date">07/18/2013</DATE>
<TIME id="time">11:53</TIME>
</EMAIL>
</EMAILCOMMENTS>
and here is css ( style for just to see if it is working, and it isn't :( )...
DATE{background-color:red;}
TIME{background-color:green;}
#date{background-color:yellow;}
#time{background-color:blue;}
BODY{background-color:grey;}
Sorry for the length of the post but I think you need all these files...
Although you can indeed style XML with CSS, using the xml-stylesheet processing instruction you have included in your XML, you can't transform it with XSLT at the same time. That is to say you should only really have one stylesheet processing instruction in your XML. Either you simply style your XML with CSS (which is not really a common thing to do), or your transform it to HTML with XSLT and style the HTML output with CSS.
In the latter case, remove the <?xml-stylesheet href="elementarray.css"?> instruction from your XML document, and instead output a reference to the CSS document in your first template.
<xsl:template match="/">
<html>
<head>
<title>E-mail</title>
<link href="elementarray.css" type="text/css" rel="stylesheet" />
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
Now, in your CSS, I see you already have selectors for the date and time ids, so you need to ensure the relevant elements in your HTML have these ids.
At the moment, you are doing this in your XSLT
<span>
<xsl:attribute name="id"><xsl:value-of select="date"/></xsl:attribute>
<!-- --><xsl:value-of select="DATE"/><!-- --></span>
<span>
But this is setting the id attribute to have the value of the date element in your XML, but such an element does not exist! I think you meaning to use the literal string here. Now, you could do this...
<xsl:attribute name="id"><xsl:value-of select="'date'"/></xsl:attribute>
But this is verbose. You can just do this:
<xsl:attribute name="id">date</xsl:attribute>
But better still, just write it out as an attribute in the normal way:
<span id="date">
<xsl:value-of select="DATE"/>
</span>
And similarly for 'time'. This should ensure the two span tags get styled using your CSS in the HTML you output.

XSL datetime, remove and condense timezone into time

I'm saving some timestamps in my XML results in standard UTC format.
What I'd like to be able to do is re-convert this to human readable times. Without the timezone addendum. As far as I've been able to get so far is:
format-dateTime(
xs:dateTime(
adjust-dateTime-to-timezone(
xs:dateTime(#thevalue),xs:dayTimeDuration('P0DT4H')
)
),'[M01]/[D01]/[Y0001] [H01]:[m01]:[s01]'
)
where #thevalue is like: 2006-02-15T17:00:00
It's giving me a headache because the formatter returns a time of 17:00. If I peel back a layer of the format-dateTime to see what the adjust-dateTime function returns, it gives
2006-02-15T17:00:00+04:00
... and all I really want to see is 21:00... so very frustrated. Anyone deal with this before?
Here is a transformation that does what you want:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vDateTime" as="xs:dateTime"
select="xs:dateTime('2006-02-15T17:00:00+00:00')"/>
<xsl:template match="/">
<xsl:sequence select=
"adjust-dateTime-to-timezone($vDateTime,
xs:dayTimeDuration('P0DT4H')
)"/>
</xsl:template>
</xsl:stylesheet>
When applied to any XML document (not used), the result is:
2006-02-15T21:00:00+04:00
And the complete solution is:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vDateTime" as="xs:dateTime"
select="xs:dateTime('2006-02-15T17:00:00+00:00')"/>
<xsl:template match="/">
<xsl:variable name="vadjustedDateTime" select=
"adjust-dateTime-to-timezone($vDateTime,
xs:dayTimeDuration('P0DT4H')
)"/>
<xsl:sequence select=
"format-dateTime($vadjustedDateTime,
'[M01]/[D01]/[Y0001] [H01]:[m01]:[s01]'
)
"/>
</xsl:template>
</xsl:stylesheet>
which produces this result:
02/15/2006 21:00:00

Select/Output unique values

I need to loop through an XML document (no problem over there) and check if a value that i find is already in a (a) tag in a div in my XSL document that i am generating, only if the value is not in that (a) tag i should create a new (a) tag for it and put in in the div that i am checking...
Any one knows how to do it dynamically in XSLT?
<div id="tags"><span class="l_cap"> </span>
all
<xsl:for-each select="root/nodes/node/data/genres">
<xsl:for-each select="value">
**<xsl:if test="not(contains())">**
<xsl:value-of select="current()"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
 
sorry for before, what i am trying to do is: in the if statement, check if the current value is already exist in the div if not, add it, if is, don't do anything...
10x again
It sounds like you're trying to create a distinct list of all of the "genres" in your list.
Assuming a data structure which looks a bit like this:
<root>
<nodes>
<node>
<data>
<genres>
<value>One</value>
<value>Two</value>
<value>Two</value>
<value>Three</value>
<value>Two</value>
</genres>
</data>
</node>
</nodes>
</root>
And a stylesheet which looks a bit like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="genres" match="value" use="."/>
<xsl:template match="/">
<div>
<xsl:for-each select="/root/nodes/node/data/genres/value">
<xsl:if test="generate-id(.) = generate-id(key('genres', .)[1])">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</div>
</xsl:template>
</xsl:stylesheet>
Then you will end up with something like this:
<div>
One
Two
Three
</div>
This is a fairly standard XSLT 1.0 technique. It uses keys (described here: http://www.xml.com/pub/a/2002/02/06/key-lookups.html ) to create a sort of index of all the /root/nodes/node/data/genres/value entries. Then it loops through all of the entries, but only prints the first one of each type. The end result is that each value will only be output once.

Resources