1
votes

I got a question, I try to convert an XML to JSON using XSLT version 1.0. As far as the name goes I get it right but the value is another story.

<datapost>
<fields>
    <field>
        <id>emailId</id>
        <name>emailName</name>
        <values>
            <value>[email protected]</value>
        </values>
    </field>
</fields>

AS IT CURRENTLY IS:

At the moment I get only the "name" correct but the "value" (emailIdName & emailId & [email protected]) is all the values squashed together what I obviously don't want.

{
    "emailName":{
        "[email protected]"
    }
}

EXPECTED TO BE:

I want to get only the "name" and the "value" in values ([email protected]) This is the result that I WANT to get:

    {
    "emailName":{
        "[email protected]"
    }
}

This is the code I use:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="no" encoding="UTF-16" omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <body>{

            <xsl:call-template name="fieldsName"></xsl:call-template>
            <xsl:text>&#13;&#10;</xsl:text>
        </body>
    </xsl:template>
    <xsl:template name="fieldsName">
        <xsl:for-each select="//datapost[position()=1]/fields/field">
        "
            <xsl:value-of select="name"/>" : 
            <xsl:call-template name="fieldsValue"/>}

        </xsl:for-each>
    </xsl:template>
    <!-- Array Element -->
    <xsl:template match="*" mode="ArrayElement">
        <xsl:call-template name="fieldsValue"/>
    </xsl:template>
    <!-- Object Properties -->
    <xsl:template name="fieldsValue">
        <xsl:variable name="childName" select="//datapost[position()=1]/fields/field/values/value"/>
        <xsl:choose>
            <xsl:when test="not(*|@*)">"
                <xsl:value-of select="."/>"
            </xsl:when>
            <xsl:when test="count(*[name()=$childName]) > 1">{ "
                <xsl:value-of select="$childName"/>" :[
                <xsl:apply-templates select="*" mode="ArrayElement"/>] }
            </xsl:when>
            <xsl:otherwise>{

                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="*"/>
          }
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="following-sibling::*">,</xsl:if>
    </xsl:template>
    <!-- Attribute Property -->
    <xsl:template match="@*">"
        <xsl:value-of select="name"/>" : "
        <xsl:value-of select="."/>",
    </xsl:template>
</xsl:stylesheet>
1

1 Answers

0
votes

The element names in your XML are poorly chosen, and this has probably confused you (it certainly confused me). One would expect "field" to contain a single field, but it actually contains all of them. So change

<xsl:for-each select="//datapost[position()=1]/fields/field">

to

<xsl:for-each select="//datapost[position()=1]/fields/field/*">

or better still,

<xsl:for-each select="datapost/fields/field/*">

since the other parts of the expression are redundant verbiage.

Then you need to look at the template containing the variable

<xsl:variable name="childName" select="//datapost[position()=1]/fields/field/values/value"/>

This is selecting all the values in the document, not just the values of the current element. I'm not entirely sure what you're trying to achieve here, and it doesn't seem to be covered by your test data, but I suspect you're trying to do some kind of grouping of elements that have the same name. For that you need to use grouping facilities: xsl:for-each-group in XSLT 2.0+, Muenchian grouping in XSLT 1.0. You haven't said which XSLT version you're using, but all of this would be an awful lot easier if you used XSLT 2.0+.