xslt - Follow-up: create (grand)parent-child elements based on delimiter in attribute-values -


hereby followup question posted here last year. still being newbie i'm struggling (again...) transform - using xslt 1.0 - following xml describes objects (note slight change in input - 'b.c.*' - previous question):

<data>     <object>         <property name="id" value="001"/>         <property name="p.id" value="id p"/>         <property name="p.description" value="descr p"/>         <property name="a.id" value="id a" />         <property name="a.description" value="descr a"/>         <property name="b.id" value="id b"/>         <property name="b.description" value="descr b"/>         <property name="b.c.id" value="b.c.id"/>         <property name="b.c.description" value="b.c.description"/>     </object> </data> 

the following rules should apply desired output:

  1. for each 'property'-element not contain separator '.' in 'name'-attribute, transform 'name'-attribute child-element , select value of 'value'-attribute.
  2. for each 'property'-element does contain separator(s) '.' in 'name'-attribute, create:
    • a) (grand)parent element using 'substring-before' separator in 'name'-attribute - 'recursively until last occurence' (not sure how describe; see desired output below), and
    • b) child element using 'substring-after' last separator in 'name'-attribute , select value of 'value'-attribute.

the desired output should therefore this:

<?xml version="1.0" encoding="utf-8"?> <root>     <objectdata>         <id>001</id>         <p>             <id>id p</id>             <description>descr p</description>         </p>         <a>             <id>id a</id>             <description>descr a</description>         </a>         <b>             <id>id b</id>             <description>descr b</description>             <c>                 <id>b.c.id</id>                 <description>b.c.description</c.description>             </c>         </b>     </objectdata> </root> 

currently have following code:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output indent="yes"/>      <xsl:key name="kpropertybyname" match="property[contains(@name, '.')]" use="concat(generate-id(..), '|', substring-before(@name,'.'))"/>      <xsl:template match="data">         <root>             <xsl:apply-templates/>         </root>     </xsl:template>      <xsl:template match="object">         <objectdata>             <xsl:apply-templates select="property[not(contains(@name, '.'))]"/>                 <xsl:for-each select="property[generate-id(.) =                      generate-id(key('kpropertybyname',                     concat(generate-id(..), '|', substring-before(@name,'.')))[1])                     ] ">                 <xsl:apply-templates select="." mode="parent"/>                 </xsl:for-each>         </objectdata>     </xsl:template>      <xsl:template match="property[not(contains(@name, '.'))]">         <xsl:element name="{@name}">             <xsl:value-of select="@value"/>         </xsl:element>     </xsl:template>      <xsl:template match="property[(contains(@name, '.'))]" mode="parent">         <xsl:element name="{substring-before(@name,'.')}">             <xsl:apply-templates mode="child" select="../property[                 substring-before(current()/@name,'.') =                  substring-before(./@name,'.')]"/>         </xsl:element>     </xsl:template>      <xsl:template match="property[(contains(@name, '.'))]" mode="child">         <xsl:element name="{substring-after(@name,'.')}">             <xsl:value-of select="@value"/>         </xsl:element>     </xsl:template> </xsl:stylesheet> 

which gives me following output - having (unwanted) 'non-separated' c.*-elements:

<?xml version="1.0" encoding="utf-8"?> <root>     <objectdata>         <id>001</id>         <p>             <id>id p</id>             <description>descr p</description>         </p>         <a>             <id>id a</id>             <description>descr a</description>         </a>         <b>             <id>id b</id>             <description>descr b</description>             <c.id>b.c.id</c.id>             <c.description>b.c.description</c.description>         </b>     </objectdata> </root> 

not i'm looking for... appreciated again!

interesting problem, have time solve xslt 2.0:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform"     xmlns:xs="http://www.w3.org/2001/xmlschema"     xmlns:mf="http://example.com/mf"     exclude-result-prefixes="xs mf"     version="2.0">  <xsl:output indent="yes"/>  <xsl:template match="@* | node()">   <xsl:copy>     <xsl:apply-templates select="@* | node()"/>   </xsl:copy> </xsl:template>  <xsl:function name="mf:group" as="element()*">   <xsl:param name="elements" as="element()*"/>   <xsl:param name="index" as="xs:integer"/>   <xsl:for-each-group select="$elements" group-adjacent="tokenize(@name, '\.')[$index]">     <xsl:choose>       <xsl:when test="not(current-group()[2])">         <xsl:apply-templates select="."/>       </xsl:when>       <xsl:otherwise>         <xsl:element name="{current-grouping-key()}">           <xsl:apply-templates select="current-group()[$index = count(tokenize(@name, '\.'))]"/>           <xsl:sequence select="mf:group(current-group()[not($index = count(tokenize(@name, '\.')))], $index + 1)"/>         </xsl:element>       </xsl:otherwise>     </xsl:choose>   </xsl:for-each-group> </xsl:function>  <xsl:template match="object">   <xsl:copy>     <xsl:sequence select="mf:group(*, 1)"/>   </xsl:copy> </xsl:template>  <xsl:template match="property[@name]">   <xsl:element name="{tokenize(@name, '\.')[last()]}">     <xsl:value-of select="@value"/>   </xsl:element> </xsl:template>  </xsl:stylesheet> 

Comments

Popular posts from this blog

java - Plugin org.apache.maven.plugins:maven-install-plugin:2.4 or one of its dependencies could not be resolved -

Round ImageView Android -

How can I utilize Yahoo Weather API in android -