Page 1 of 1

XSLT: Generate ID

Posted: Fri Sep 14, 2018 2:39 pm
by HuubT
Hello,

I am new to XSLT transformation and looking for someone some get me on the way.

I have this (example) XML:

<Loonaangifte xmlns="http://xml.belastingdienst.nl/schemas/L ... te/2018/01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml.belastingdienst.nl/schemas/L ... te/2018/01 loonaangifte.xsd" version="2.0">
<AdministratieveEenheid>
<TijdvakAangifte>
<Date>01-01-2018</Date>
</TijdvakAangifte>
<TijdvakAangifte>
<Date>02-01-2018</Date>
</TijdvakAangifte>
<TijdvakAangifte>
<Date>03-01-2018</Date>
</TijdvakAangifte>
</AdministratieveEenheid>
</Loonaangifte>

I want to insert an ID <TijdvakAangifteId> before the <Date> field.
Could anyone please provide me with a proper .xls file to achieve this.

Many thanks!

HuubT

Re: XSLT: Generate ID

Posted: Fri Sep 14, 2018 4:53 pm
by Martin Honnen
So what kind of ID are you looking for?

In general assuming you have a version of oXygen that supports XSLT 3 all such stylesheet that need to perform a transformation of some nodes but keep the rest of the document unchanged would start with

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

</xsl:stylesheet>
then, as your input elements are in a certain namespace and you want to match them you would declare that namespace as the xpath-default-namespace with e.g.

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">
and as you also want to create new elements in your XSLT declare the namespace there as the default namespace

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
xmlns="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">
and now you are ready to write template for those elements you want to transform/change so you want e.g.

Code: Select all


  <xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:number count="TijdvakAangifte"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>
will add the new element before the "Date" (which will itself simply be copied by relying on "next-match" which uses the built-in copy declared with the "mode" already).

So the complete stylesheet uses

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
xmlns="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:number count="TijdvakAangifte"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>

</xsl:stylesheet>
You will need to adjust the "ID" computation where I simply count the parent of the "Date" as needed as you haven't really explained what kind of id you are looking for.

Code: Select all


  <xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:value-of select="generate-id()"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>
for instance would give you whatever the XSLT processor generates for the matched "Date" element.

Re: XSLT: Generate ID

Posted: Fri Sep 14, 2018 9:11 pm
by HuubT
Thanks for your support; it helped me a lot.

Re: XSLT: Generate ID

Posted: Sat Sep 15, 2018 10:08 am
by HuubT
Martin Honnen wrote:So what kind of ID are you looking for?

In general assuming you have a version of oXygen that supports XSLT 3 all such stylesheet that need to perform a transformation of some nodes but keep the rest of the document unchanged would start with

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

</xsl:stylesheet>
then, as your input elements are in a certain namespace and you want to match them you would declare that namespace as the xpath-default-namespace with e.g.

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">
and as you also want to create new elements in your XSLT declare the namespace there as the default namespace

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
xmlns="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">
and now you are ready to write template for those elements you want to transform/change so you want e.g.

Code: Select all


  <xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:number count="TijdvakAangifte"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>
will add the new element before the "Date" (which will itself simply be copied by relying on "next-match" which uses the built-in copy declared with the "mode" already).

So the complete stylesheet uses

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
xmlns="http://xml.belastingdienst.nl/schemas/Loonaangifte/2018/01"
exclude-result-prefixes="#all"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:number count="TijdvakAangifte"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>

</xsl:stylesheet>
You will need to adjust the "ID" computation where I simply count the parent of the "Date" as needed as you haven't really explained what kind of id you are looking for.

Code: Select all


  <xsl:template match="TijdvakAangifte/Date">
<TijdvakAangifteId>
<xsl:value-of select="generate-id()"/>
</TijdvakAangifteId>
<xsl:next-match/>
</xsl:template>
for instance would give you whatever the XSLT processor generates for the matched "Date" element.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Hello Martin,

Thanks for your input.
I have another question. Is it possible to inject a parent id (based on number count) into a child section?
Like this:
<Root>
<LevelA>
<LevelAId>1</LevelAId>
<LevelAName>xxxxxx<//LevelAName>
<LevelB>
<LevelBId>1</LevelBId>
<LevelAId>1</LevelAId>
<LevelBName>yyyyy</LevelBName>
</LevelB>
</LevelA>
etc.
<?Root>

Would help me a lot!

With kind regards,

HuubT

Re: XSLT: Generate ID

Posted: Sat Sep 15, 2018 12:02 pm
by HuubT
Hello Martin,

Thanks for your input.
I have another question regarding parent-child relationships.

How can I achieve the injection of <ParenId> in <Parent> and <Child> sections in the example below?

<Root>
<Parent>
<ParentId>1</ParentId>
<ParentName>P1</ParentName>
<Child>
<ChildId>1</ChildId>
<ParentId>1</ParentId>
<ChildName>C1</ChildName>
</Child>
<Child>
<ChildId>2</ChildId>
<ParentId>1</ParentId>
<ChildName>C2</ChildName>
</Child>
</Parent>
etc.
</Root>

Thanks for your answer.

With kind regards,

HuubT

Re: XSLT: Generate ID

Posted: Mon Sep 17, 2018 11:08 pm
by Martin Honnen
HuubT wrote: I have another question regarding parent-child relationships.

How can I achieve the injection of <ParenId> in <Parent> and <Child> sections in the example below?

<Root>
<Parent>
<ParentId>1</ParentId>
<ParentName>P1</ParentName>
<Child>
<ChildId>1</ChildId>
<ParentId>1</ParentId>
<ChildName>C1</ChildName>
</Child>
<Child>
<ChildId>2</ChildId>
<ParentId>1</ParentId>
<ChildName>C2</ChildName>
</Child>
</Parent>
etc.
</Root>
Consider to ask a new question in a separate question, in general you can use the `xsl:number` https://www.w3.org/TR/xslt-30/#number element quite well to compute such numbers by using an appropriate pattern, if that is what you are looking for. If the "ParentId" is already in the "Parent" element and you simply want to copy it to the "ParentId" of the child you would navigate up e.g.

Code: Select all


<xsl:template match="Child">
<xsl:copy>
<xsl:copy-of select="ChildId, ../ParentId, ChildName"/>
</xsl:copy>
</xsl:template>