really I canot find it how to change this duration notification
PT11H22M to 11.22
but it seems like easy comand
Suppose that you have the value "PT11H22M" as a string:
<xsl:variable name="s" as="xs:string" select="'PT11H22M'"/>
Assuming your duration is always less than 24 hours, you can convert the string "PT11H22M" to a duration using
<xsl:variable name="d" as="xs"dayTimeDuration"
select="xs:dayTimeDuration($s)"/>
You can then convert this to a time-of-day using
<xsl:variable name="t" as="xs:time" select="xs:time('00:00:00') + $d"/>
And you can then format this as the string "11.22" using
<xsl:variable name="out" as="xs:string"
select="format-time($t, '[H01].[m01]')"/>
Alternatively you can extract the hours and minutes components of a duration using fn:hours-from-duration and fn:minutes-from-duration, and then format these as numbers using fn:format-number.
Related
I need to convert 11/14/2016 - This is String Data Type. I need to convert it to 2016-11-14 using XSLT 2.0. Please let me know how to proceed? I don't want to use subString method. I tried format-date() function from xslt 2.0 but not successful.
You could do something like this. You can use the tokenize function instead, if you do not want to use substring.
Assuming an input XML like:
<string>11/14/2016</string>
When run against a style sheet below:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="target_string">
<xsl:value-of select="tokenize(string, '/')[last()]"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="tokenize(string, '/')[1]"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="tokenize(string, '/')[2]"/>
</xsl:variable>
<date1>
<xsl:value-of select="xs:date($target_string)"/>
</date1>
<date2>
<xsl:value-of select="format-date(xs:date($target_string), '[MNn] [D], [Y]')"/>
</date2>
</xsl:template>
</xsl:stylesheet>
produces:
<date1>2016-11-14</date1><date2>November 14, 2016</date2>
Sorry to say that XSLT is following ISO 8601 which should be yyyy-mm-dd, so subString will be your only choice.
Reference:
https://www.w3.org/TR/xmlschema-2/#isoformats
I would like to parse almost free format String to DateTime in XSL-T 3.0 as one can do it in Java using java.text.SimpleDateFormat. Is it possible?
I am using the latest Saxon HE 9.7.0.1 for Java and consulting it with the W3C CR 3.1 "XPath and XQuery Functions and Operators 3.1". There is the function "fn:parse-ietf-date" in W3C CR 3.1, but it does not look like it can parse String like "6.1.94 7:29" - the Exception:
Error at char 17 in xsl:value-of/#select on line 20 column 47 of tr.xsl:
FORG0010: Invalid IETF date value 6.1.94 7:29 (Date separator missing)
in built-in template rule
Invalid IETF date value 6.1.94 7:29 (Date separator missing)
Do I make any error in my XSL-T or "fn:parse-ietf-date" does not support more formats of String to be parsed to DateTime?
If the problem is not on my side, could it be possible to add function like fn:parseTime to the W3C CR 3.1 as the "copy" of Java 8 java.text.SimpleDateFormat class with the support of all its Date and Time Patterns? It could solve the parsing of String to DateTime (I hope forever). Also it is already invented in Java and used widely. Implementing it in Saxon-HE would be very appreciated by me, although I know, it should be quite easy to call java.text.SimpleDateFormat in Saxon-PE or Saxon-EE in my XSL-T script.
Regards, Stepan
My use-case:
shell:
java -jar .\saxon9he.jar -t -s:.\in.xml -xsl:.\tr.xsl -o:.\out.xml
in.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>6.1.94 7:29</root>
tr.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:template
match="/root">
<xsl:element
name="root">
<xsl:element
name="originalValue">
<xsl:value-of
select="./text()"/>
</xsl:element>
<xsl:element
name="newValue">
<xsl:value-of
select="parse-ietf-date(./text())"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The function parse-ietf-date is specifically for parsing dates used in various IETF standards, which are rather US-centric (for example, they always express the month as an English month name, and use (month, day, year) order. It was not designed as a general-purpose solution for dates in arbitrary formats.
You choice is basically either (a) to invoke a general-purpose date parser in Java, via extension functions, or (b) to write XSLT code to parse the specific date formats you want to handle.
A parse-date() function has been defined in the EXSLT date handling library for years: see http://exslt.org/date/functions/parse-date/index.html - but it has not been widely implemented, and is not implemented in Saxon.
I have a xml file in which one of the element has the CDATA as the value. I put the CDATA value into a variable which I can see is value type of document-node(1) when i debug my code from oXygen. How do I iterate the document-node()?
copy can give me a new xml file. but what I need is not a new file. I only need to read certain nodes and generate a report based on the values on those nodes. so I directly copy the CDATA to my variable and thought I can manipulate it.
I tried to use substring to read the variable things but failed.
I tried to use document(variable) to open the variable but Oxygen give me the debug-error of FODC0002:I/O error reported by xml parser processing file.
here the file is my variable which looks like a xml file
I did google search for the error but only got bench of non-closed questions like Oxygen throw I/O error when use document().
Would anybody let me know what's going wrong? or give me a better solution?
I also tried parse-xml() but I got the following error from Saxon:
F[Saxon-EE9.5.1.5] the processing instruction target matching "[xX][mM][lL]" is not allowed
F[Saxon-EE9.5.1.5] FODC0006: First argument to parse-xml() is not a well formed and namespace-well-formed XML document.
my code to use parse-xml is as below:
<xsl:template match="data"
<xsl:for-each select="parse-xml(root/outsideData)//nodeLevel1/nodeLevel2">
Could anyone give me a sample about how to use parse-xml()? I did google search but didn't find useful samples.
Thanks very much!
A piece of my data is like the following:
<root>
<outsideData id="123">
<child1 key="124375438"/>
<![CDATA[ <?xml version=1.0 encoding="UTF-8"?><insideData xmlns:xlink="http://www.w3.org/1999/xlink">
<nodeLevel1>
<nodeLevel21>packing</nodeLevel21>
<nodeLevel22 ref="12343-454/560" xlink:href="URN:X-MN:DD%3FM=B888%26SDC=A%26CH=79% .../>
</nodeLevel1>
]]>
</outsideData>
</root>
I want to get the inside CDATA <nodeLevel22> #ref and #xlink which will get DD-FM-B888-26-79
My variables are:
<xsl:for-each select="/root/outsideData">
<xsl:variable name="insideData">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:variable>
<xsl:variable name="Data">
<xsl:value-of
select="normalize-space(substring-after($insideData,'?>'))"
disable-output-escaping="yes"/>
</xsl:variable>
</xsl:foreach>
From the debug I can see that the variable insideData and Data are both value type of document-node(1)
Martin's solution works for me very well :)
But I'm still wondering why the following doesn't work:
<xsl:variable name="insideData">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:variable>
<ref>
<xsl:value-of select="substring-before(substring-after($insideData, '<nodeLevel22 ref'),>/>')"/>
</ref>
Here I got empty <ref/>
If you do <xsl:variable name="varName"><xsl:value-of select="..."/><xsl:variable> then you are creating a temporary document fragment that contains a single text with the string contents of the item(s) selected in the value-of. That does not make sense in most cases, doing <xsl:variable name="varName" select="..."/> is usually sufficient.
As for parsing the contents of the outsideData element with parse-xml, there is indeed not only the escaped XML document inside that element but white space as well, thus if you try to parse the contents as XML you get that error as white space before the XML declaration is not allowed. The whole approach of stuffing the XML into a CDATA section with an element with mixed contents is flawed in my view, if you want to store escaped XML into a CDATA then you should make sure that you use a single element that contains nothing but the CDATA section which then only contains the XML markup with no leading white space.
If you can't change the creation of the input data then you will need to make sure you pass in only that part of the string contents of the element to parse-xml that is a well-formed XML document, so you need some way to strip the white space before the XML declaration doing e.g.
<xsl:for-each select="/root/outsideData">
<xsl:variable name="xml-string" select="replace(., '^\s+', '')"/>
<xsl:variable name="xml-doc" select="parse-xml($xml-string)"/>
<!-- now output data e.g. -->
<xsl:value-of select="$xml-doc//nodeLevel1/nodeLevel22/#ref"/>
...
</xsl:for-each>
Untested but should show the right direction as far as trying to use parse-xml.
I've an XML line like the below.
<title>I. DEFINITION</title>
Here what i'm doing getting the value before '.', this is fine but i want to apply-templates for the content after '.'. i'm unable to know how do i do it. i'm using the below XSLT line.
<xsl:apply-templates select="substring-after(.,'. ')"/>
when i use it, an error is thrown and it is
XSLT 2.0 Debugging Error: Error: file:///C:/Users/u0138039/Desktop/Proview/HK/ArchboldHK2014/XSLT/Chapters.xsl:508: Not a node item - item has type xs:string with value 'DEFINITION' - Details: - XTTE0520: The result of evaluating the 'select' attribute of the <xsl:apply-templates> instruction may only contain nodes
please let me know how i can apply-templates on content after '.'
Thanks.
You can try this template
<xsl:template match="title">
<xsl:copy>
<label><xsl:value-of select="substring-before(., '. ')"/></label>
<caption>
<xsl:variable name="slicetext" select="substring-after(current()/text()[1], '. ')"/>
<xsl:value-of select="$slicetext"/><xsl:apply-templates select="text()[position() > 1]|child::node()[not(self::text())]"/>
</caption>
</xsl:copy>
</xsl:template>
With XSLT 1.0 and 2.0 you can only write and apply-templates for nodes, not for primitive values like strings. I think this changes in XSLT 3.0.
In XSLT 2.0, to process the result of substring-after further, you would need to write a function or a named template taking a string parameter.
If you really want to apply a template you first would need to create a temporary text node with xsl:variable.
I would like to parse a youtube url using XSLT and get only the Video ID from that URL. What's the best way to do this using XSLT?
So, if the url is: http://www.youtube.com/watch?v=qadqO3TOvbQ&feature=channel&list=UL
I only want qadqO3TOvbQ and put it into an embed code:
<iframe width="560" height="315" src="http://www.youtube.com/embed/qadqO3TOvbQ" frameborder="0" allowfullscreen=""></iframe>
I. This XPath 2.0 expression:
substring-after(tokenize($pUrl, '[?|&]')[starts-with(., 'v=')], 'v=')
produces the wanted, correct result.
Alternatively, one can use the slightly shorter:
tokenize(tokenize($pUrl, '[?|&]')[starts-with(., 'v=')], '=')[2]
Here is a complete XSLT 2.0 transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pUrl" select=
"'http://www.youtube.com/watch?v=qadqO3TOvbQ&feature=channel&list=UL'"/>
<xsl:template match="/">
<xsl:sequence select=
"tokenize(tokenize($pUrl, '[?|&]')[starts-with(., 'v=')], '=')[2]"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), the wanted, correct result is produced:
qadqO3TOvbQ
II. This XPath 1.0 expression:
concat
(substring-before(substring-after(concat($pUrl,'&'),'?v='),'&'),
substring-before(substring-after(concat($pUrl,'&'),'&v='),'&')
)
produces the wanted result.
Do note:
Both solutions extract the wanted string even if the query string parameter named v isn't the first one or even in the case when it is the last one.
XSLT/XPath is not best suited to string handling (1.0 especially) but you can achieve what you need by mixing up the substring-after() and substring-before() functions:
<xsl:value-of select="substring-before(substring-after($yt_url, '?v='), '&feature')" />
(assumes the YT URL is stored in an XSLT var, $yt_url, and that it has its & escaped to &).
Demo at this this XML Playground