Following previous post:
Graph data model to transform XML to RDF
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sbase="http://my.semantics/projects/" xmlns:spi="http://my.semantics/projects/incentive/" version="2.0">
<xsl:template match="projects">
<xsl:element name="rdf:RDF">
<xsl:for-each select="project">
<xsl:element name="rdf:Description">
<xsl:attribute name="rdf:about" select="concat('http://my.semantics/projects/incentive/', projectID)" />
<xsl:attribute name="sbase:program" select="program" />
<xsl:attribute name="sbase:projectID" select="projectID" />
<xsl:attribute name="sbase:projectName" select="projectName" />
<xsl:attribute name="sbase:recipient" select="recipient" />
<xsl:element name="sbase:about">
<xsl:attribute name="rdf:resource" select="'http://my.semantics/ontology/economy'" />
</xsl:element>
<xsl:element name="spi:postalCode">
<xsl:value-of select="postalCode" />
</xsl:element>
<xsl:element name="spi:region">
<xsl:value-of select="region" />
</xsl:element>
<xsl:element name="spi:industry">
<xsl:value-of select="industry" />
</xsl:element>
<xsl:element name="spi:incentiveType">
<xsl:value-of select="incentiveType" />
</xsl:element>
<xsl:element name="spi:startDate">
<xsl:value-of select="startDate" />
</xsl:element>
<xsl:element name="spi:totalAwarded">
<xsl:value-of select="totalAwarded" />
</xsl:element>
<xsl:element name="spi:totalInvestment">
<xsl:value-of select="totalInvestment" />
</xsl:element>
<xsl:element name="spi:disbursementsToDate">
<xsl:value-of select="disbursementsToDate" />
</xsl:element>
<xsl:element name="rdf:comment">
<xsl:value-of select="projectDescription" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:transform>
If I use sem:rdf-insert(xdmp:xslt-eval($rdf-xml, $doc),"rdfxml", (), "rdf-incentive"), I got error:
XDMP-AS: (err:XPTY0004) $triples as sem:triple* -- Invalid coercion: xs:untypedAtomic() as sem:triple
If sem:rdf-load((xdmp:xslt-eval($rdf-xml,$doc)),"rdfxml",(),(),"rdf-incentive")
I got error:
SVC-FILOPN: xdmp:document-get()…: No such file or directory
Given the complexity of RDF syntax, you can consider
separate XSL to declare shared RDF attributes
<xsl:attribute-set name="incentiveRDFAttr">
<xsl:attribute name="rdf:about" select="concat('http://my.semantics/projects/incentive/', projectID)"/>
<xsl:attribute name="sbase:program" select="program"/>
<xsl:attribute name="sbase:projectID" select="projectID"/>
<xsl:attribute name="sbase:projectName" select="projectName"/>
<xsl:attribute name="sbase:recipient" select=" recipient"/>
</xsl:attribute-set>
<xsl:attribute-set name="rdfDataTime">
<xsl:attribute name="rdf:datatype" select="'http://www.w3.org/2001/XMLSchema#dateTime'"/>
</xsl:attribute-set>
<xsl:attribute-set name="rdfDecimal">
<xsl:attribute name="rdf:datatype" select="'http://www.w3.org/2001/XMLSchema#decimal'"/>
</xsl:attribute-set>
««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»«»»««»»««»»««»»
call the attribute XSL in the main RDF transform XSL
<!-- Ingested attribute XSL in module database -->
<xsl:include href="/xsl/rdf-attributes.xsl"/>
<xsl:template match="projects">
<xsl:element name="rdf:RDF">
<xsl:for-each select="project">
<xsl:element name="rdf:Description" use-attribute-sets="incentiveRDFAttr">
««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»«»»««»»««»»««»»
<xsl:element name="spi:startDate" use-attribute-sets="rdfDataTime"><xsl:value-of select="normalize-space(startDate)"/></xsl:element>
<xsl:element name="spi:totalAwarded" use-attribute-sets="rdfDecimal"><xsl:value-of select="normalize-space(totalAwarded)"/></xsl:element>
««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»««»»«»»««»»««»»««»»
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
Please use sem:rdf-parse to serialise RDF triples after XSL transform and during ingestion:
sem:rdf-insert(
sem:rdf-parse(xdmp:xslt-eval($rdf-xml, $doc), "rdfxml"),
("rdfxml", "directory=/my/semantics/"),
(),
"rdf-incentive"
)
Related
I need to group the company and the maximum number the node row can occur in the new node group is 3.
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:decimal-format name="coerce" NaN="0"/>
<xsl:template match="/root">
<root>
<!--Group by fields, can only group by 1 element each time-->
<xsl:for-each-group select="row" group-by="Company">
<xsl:for-each-group select="current-group()" group-by="Department">
<xsl:for-each select="current-group()">
<!--Create a variable for the row count-->
<xsl:variable name="Grpcounter" select="number(position())"/>
<xsl:if test="$Grpcounter < 3">
<xsl:call-template name="Group">
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:for-each-group>
</xsl:for-each-group>
</root>
</xsl:template>
<xsl:template name="Group">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
could you pls update your xslt as follows:
replace: <xsl:template match="/root"> . . . </xsl:template> with
<xsl:template match="/root">
<xsl:variable name="grouped">
<!--Group by fields, can only group by 1 element each time-->
<xsl:for-each-group select="row" group-by="Company">
<!--<xsl:for-each-group select="current-group()" group-by="Department">-->
<xsl:for-each select="current-group()">
<xsl:choose>
<xsl:when test="position() mod 3 = 1">
<Group>
<xsl:call-template name="Group"/>
</Group>
</xsl:when>
<xsl:otherwise>
<Group1>
<xsl:call-template name="Group"/>
</Group1>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!--</xsl:for-each-group>-->
</xsl:for-each-group>
</xsl:variable>
<root>
<xsl:for-each-group select="$grouped/*" group-starting-with="Group">
<Group>
<xsl:copy-of select="current-group()/row"/>
</Group>
</xsl:for-each-group>
</root>
</xsl:template>
to get your expected output. See result
My input values are "Tue, 12 Sep 2017 15:03:22 EDT" or "2017-09-12T15:03:22.0000000". I need something like: ""2017-09-12T19:03:22Z""
Is it possible to convert EDT date-time to GMT format in XSLT 1.0?
To convert between two timezones with a known offset between them in pure XSLT 1.0, you can use the following example:
XML
<input>2017-09-12T15:03:22.0000000</input>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="input">
<output>
<xsl:call-template name="add-hours-to-dateTime">
<xsl:with-param name="dateTime" select="."/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="add-hours-to-dateTime">
<xsl:param name="dateTime"/>
<xsl:param name="hours" select="4"/>
<xsl:variable name="dateTime-in-seconds">
<xsl:call-template name="dateTime-to-seconds">
<xsl:with-param name="dateTime" select="$dateTime"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="total-seconds" select="$dateTime-in-seconds + 3600 * $hours" />
<!-- new date -->
<xsl:variable name="new-date">
<xsl:call-template name="JDN-to-Gregorian">
<xsl:with-param name="JDN" select="floor($total-seconds div 86400)"/>
</xsl:call-template>
</xsl:variable>
<!-- new time -->
<xsl:variable name="t" select="$total-seconds mod 86400" />
<xsl:variable name="h" select="floor($t div 3600)" />
<xsl:variable name="r" select="$t mod 3600"/>
<xsl:variable name="m" select="floor($r div 60)"/>
<xsl:variable name="s" select="$r mod 60"/>
<!-- output -->
<xsl:value-of select="$new-date" />
<xsl:text>T</xsl:text>
<xsl:value-of select="format-number($h, '00')"/>
<xsl:value-of select="format-number($m, ':00')"/>
<xsl:value-of select="format-number($s, ':00.###')"/>
</xsl:template>
<xsl:template name="dateTime-to-seconds">
<xsl:param name="dateTime"/>
<xsl:variable name="date" select="substring-before($dateTime, 'T')" />
<xsl:variable name="time" select="substring-after($dateTime, 'T')" />
<xsl:variable name="year" select="substring($date, 1, 4)" />
<xsl:variable name="month" select="substring($date, 6, 2)" />
<xsl:variable name="day" select="substring($date, 9, 2)" />
<xsl:variable name="hour" select="substring($time, 1, 2)" />
<xsl:variable name="minute" select="substring($time, 4, 2)" />
<xsl:variable name="second" select="substring($time, 7)" />
<xsl:variable name="a" select="floor((14 - $month) div 12)"/>
<xsl:variable name="y" select="$year + 4800 - $a"/>
<xsl:variable name="m" select="$month + 12*$a - 3"/>
<xsl:variable name="jd" select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
<xsl:value-of select="86400*$jd + 3600*$hour + 60*$minute + $second" />
</xsl:template>
<xsl:template name="JDN-to-Gregorian">
<xsl:param name="JDN"/>
<xsl:variable name="f" select="$JDN + 1401 + floor((floor((4 * $JDN + 274277) div 146097) * 3) div 4) - 38"/>
<xsl:variable name="e" select="4*$f + 3"/>
<xsl:variable name="g" select="floor(($e mod 1461) div 4)"/>
<xsl:variable name="h" select="5*$g + 2"/>
<xsl:variable name="D" select="floor(($h mod 153) div 5 ) + 1"/>
<xsl:variable name="M" select="(floor($h div 153) + 2) mod 12 + 1"/>
<xsl:variable name="Y" select="floor($e div 1461) - 4716 + floor((14 - $M) div 12)"/>
<xsl:value-of select="$Y" />
<xsl:value-of select="format-number($M, '-00')"/>
<xsl:value-of select="format-number($D, '-00')"/>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>2017-09-12T19:03:22</output>
I am trying to generate a counter and I do it successfully using the position() function in xslt.
How can I create a counter within a range -1001 - 9999 such that the first counter is 1001 in place of 1.
in put xml
<ROOT>
<Row>
<Var>11</Var>
</Row>
<Row>
<Var>11</Var>
</Row>
<Row>
<Var>3</Var>
</Row>
<Row>
<Var>43</Var>
</Row>
<Row>
<Var>51</Var>
</Row>
and the desired o/p is
<ROOT>
<Row>
<Var>11</Var>
<seq>1001</seq>
</Row>
<Row>
<Var>11</Var>
<seq>1002</seq>
</Row>
<Row>
<Var>3</Var>
<seq>1003</seq>
</Row>
<Row>
<Var>43</Var>
<seq>1004</seq>
</Row>
<Row>
<Var>51</Var>
<seq>1005</seq>
</Row>
..
Thanks,
Vicky
I achieved the req as below:
<xsl:template match="/">
<ROOT>
<xsl:apply-templates />
</ROOT>
</xsl:template>
<xsl:template match="ROOT/Row">
<Row>
<Var>
<xsl:value-of select="Var"/>
</Var>
<seq>
<xsl:value-of select="1000 + position()" />
</seq>
</Row>
</xsl:template>
Well, XPath 2 and later literally allows you to write 1000 to 9999 to create a sequence of those numbers. I am not sure how that fits into your problem as you haven't provided any context like input you have and output you want. In XSLT 3 (not 2) the xsl:number element often used to count or number things also has a start-at attribute, see https://www.w3.org/TR/xslt-30/#element-number.
As you seem to want to number elements from the input I think the right approach is to use xsl:number so with XSLT 3 you can simply do:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="Row">
<xsl:copy>
<xsl:apply-templates/>
<seq>
<xsl:number start-at="1001"/>
</seq>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/jyyiVhq
with XSLT 2 you can of course use xsl:number in a variable and then at 1000 e.g.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0"
exclude-result-prefixes="xs">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:template match="Row">
<xsl:copy>
<xsl:apply-templates/>
<seq>
<xsl:variable name="count" as="xs:integer"><xsl:number/></xsl:variable>
<xsl:value-of select="$count + 1000"/>
</seq>
</xsl:copy>
</xsl:template>
</xsl:transform>
http://xsltransform.hikmatu.com/jyyiVhn
I don't think it makes sense to use the to expression for your use case, it would rather be useful if you wanted to create a couple of new elements e.g.
<xsl:template match="body">
<xsl:copy>
<xsl:for-each select="1001 to 1100">
<seq>
<xsl:value-of select="."/>
</seq>
</xsl:for-each>
</xsl:copy>
</xsl:template>
Note that with XSLT 3.0 you can do
<seq>
<xsl:number start-at="1001" />
</seq>
I am trying to add an element called Stamping one time and only if it doesn't exist in the message.
<!-- Copy all other elements -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
<xsl:template match="/*[local-name()='Envelope']/*[local-name()='Body']/*/*[not(*[local-name()='Stamping'])]">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</xsl:template>
My problem occurs because the new v1:Stamping value is repeated for every child like this based on my existing match:
<envelope>
<body>
<operationName>
<child1 Catalog="1" />
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
<v1:Stamping>
<child2 Catalog="2" />
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</operationName>
</body>
</envelope>
I need to see the result where stamping is only added one time as a child element of operationName. operationName is an element that will exist but this XSLT will be applied across many services and the value in operationName will be different depending on the service where this XSLT will be applied. This example below would be the needed output.
<envelope>
<body>
<operationName>
<child1 Catalog="1" />
<child2 Catalog="2" />
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</operationName>
</body>
</envelope>
I need to see the result where stamping is only added one time as a
child element of operationName.
Then write a template especially for operationName elements:
<xsl:template match="operationName">
and check whether v1:Stamping already exists as one of its children:
<xsl:if test="not(v1:Stamping)">
If it does not exist already, it is added to the output tree.
Assuming the following XML, where there is no v1:Stamping element, as input:
XML Input
<?xml version="1.0" encoding="UTF-8"?>
<envelope>
<body>
<operationName>
<child1 Catalog="1"/>
<child2 Catalog="2"/>
</operationName>
</body>
</envelope>
Stylesheet
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:v1="http://www.v1.com" xmlns:v2="http://www.v2.com">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="operationName">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:if test="not(v1:Stamping)">
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:transform>
XML Output
<?xml version="1.0" encoding="UTF-8"?>
<envelope>
<body>
<operationName>
<child1 Catalog="1"/>
<child2 Catalog="2"/>
<v1:Stamping xmlns:v1="http://www.v1.com" xmlns:v2="http://www.v2.com">
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</operationName>
</body>
</envelope>
I'm still new to working with XSLT
How do I apply a class to an element found with an xsl:if
XML:
<ColumnBody><h3>Some Text</h3></ColumnBody>
The output that I want:
<h3 class="box-list-link">Some Text </h3>
I have something that does this:
<xsl:for-each select ="./ColumnBody" >
<xsl:call-template name="RichText"></xsl:call-template>
</xsl:for-each>
<xsl:template name="RichText">
<p>
<xsl:copy-of select="./node()" />
</p>
</xsl:template>
Would something like this work for you?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h3">
<h3 class="box-list-link">
<xsl:apply-templates/>
</h3>
</xsl:template>
</xsl:stylesheet>