XSLT: Generate ID

Here should go questions about transforming XML with XSLT and FOP.
HuubT
Posts: 4
Joined: Fri Sep 14, 2018 2:28 pm

XSLT: Generate ID

Post 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
Martin Honnen
Posts: 96
Joined: Tue Aug 19, 2014 12:04 pm

Re: XSLT: Generate ID

Post 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.
HuubT
Posts: 4
Joined: Fri Sep 14, 2018 2:28 pm

Re: XSLT: Generate ID

Post by HuubT »

Thanks for your support; it helped me a lot.
HuubT
Posts: 4
Joined: Fri Sep 14, 2018 2:28 pm

Re: XSLT: Generate ID

Post 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
HuubT
Posts: 4
Joined: Fri Sep 14, 2018 2:28 pm

Re: XSLT: Generate ID

Post 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
Martin Honnen
Posts: 96
Joined: Tue Aug 19, 2014 12:04 pm

Re: XSLT: Generate ID

Post 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>
Post Reply