How to translate an XML document in C struct using XSL

289 Views Asked by At

I have XML text formatted somewhat like this:

<root>
  <struct1>
     <el1 type="INT32" descript="Element No.1">0</el1>
     <el2 type="FLOAT32" descript="element No. 2</el2>
  </struct1>

  <struct2>
     <el3 type="INT32" descript="Element No.3">0</el3>
     <el4 type="STRING32" descript="element No. 4</el4>
  </struct2>

  <struct3>
     <el5 type="INT32" descript="Element No.5">0</el5>
     <el6 type="FLOAT32" descript="element No. 6</el6>
  </struct3>
</root>

and I want to translate this using XSLT into C code looking like this:

/*************************
* legal blah blah
************************************************************************/

#ifndef ROOT_H
#define ROOT_H

typedef struct
{
   INT32 el1;
   FLOAT32 el2;
} root_struct1_t

typedef struct
{
   INT32 el3;
   STRING32 el4;
} root_struct2_t

typedef struct
{
   INT32 el5;
   FLOAT32 el6;
} root_struct3_t

#endif

The requirement is that the header file will use the same name as the root element but in all caps and a '_H' appended (in my example, "root" so the header guard would be ROOT_H. The legal blah blah comment is always put at the head of the file. The "level 1" elements (children of the root) must get translated as "typedef struct {...} X_Y_t where X is the root element name, Y is the element name, and the '_t" a constant text. The children of these sub-elements get translated using the element name, and the type is given by the "type" attribute value.

Is there an XSL example of how to do something like this?

All the examples I found have the name of the element to be translated being the same for all elements (as in <prop name="blahblah" type="moreblah" />. That does not work for me.

The output side of this question is not so much the object of my question as "how do I extract the name of an element and some of the attributes and reuse them in the output?"

1

There are 1 best solutions below

4
On BEST ANSWER

Using XSLT 1.0:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8" indent="no" />

    <xsl:template match="/*">
        <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
        <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
#ifndef <xsl:value-of select="concat(translate(local-name(), $smallcase, $uppercase), '_H')" />
#define <xsl:value-of select="concat(translate(local-name(), $smallcase, $uppercase), '_H')" />

    <xsl:for-each select="child::*">
    typedef struct {
        <xsl:for-each select="child::*">
            <xsl:value-of select="@type" /> <xsl:text> </xsl:text> <xsl:value-of select="local-name()" />;
        </xsl:for-each>
    } <xsl:value-of select="concat(../local-name(), '_', local-name(), '_t')" />    
    <xsl:text>        
    </xsl:text>
    </xsl:for-each>

#endif
    </xsl:template>


</xsl:transform>

XSLTranform

Basic idea here is to match any root node in the template, and then iterate using the child:: axis.