I'm trying to use XSLT to change an XML to a JSON. It's actually a very simple schema but the XSLT I'm modify to use is more complicated than I need as I don't require pretty printing or arrays, besides the top level ones.
Source XML:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<r xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<GR CO="B" Date="2022-03-15" Zone="ASDF" Truck="1TR"></GR>
<BS CO="A" Date="2022-03-14" Zone="ASDF" Truck="BT1"/>
<GR CO="A" Date="2022-03-14" Zone="QWER" Truck="2TK"></GR>
</r>
All attributes would become a JSON string element following by a comma. Then append one at the end named Line with the value of the original element name. It would be nice to also sort by the Date attribute.
Pretty Print of Desired Output, but white space not needed:
{
"Routes": [
{
"CO": "A",
"Date": "2022-03-14",
"Zone": "QWER",
"Truck": "BT1",
"Line": "BS"
},
{
"CO": "A",
"Date": "2022-03-14",
"Zone": "ASDF",
"Truck": "2TK",
"Line": "GR"
},
{
"CO": "B",
"Date": "2022-03-15",
"Zone": "ASDF",
"Truck": "1TR",
"Line": "GR"
}
]
}
This is what I'm trying and I cannot make it work:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:template match="/r">
<xsl:text>{"Routes": [</xsl:text>
<xsl:apply-templates select="." mode="detect">
<xsl:sort select="./@Date" />
</xsl:apply-templates>
<xsl:text>}</xsl:text>
</xsl:template>
<xsl:template match="@*" priority="1">
<xsl:text>Found Attrib</xsl:text>
</xsl:template>
<xsl:template match="*" priority="2" mode="detect">
<xsl:text>{</xsl:text>
<xsl:choose>
<xsl:when test="name(preceding-sibling::*[1]) = name(current()) and name(following-sibling::*[1]) != name(current())">
<xsl:apply-templates select="." mode="obj-content" />
<xsl:text>]</xsl:text>
<xsl:if test="count(following-sibling::*[name() != name(current())]) > 0">, </xsl:if>
</xsl:when>
<xsl:when test="name(preceding-sibling::*[1]) = name(current())">
<xsl:apply-templates select="." mode="obj-content" />
<xsl:if test="name(following-sibling::*) = name(current())">, </xsl:if>
</xsl:when>
<xsl:when test="following-sibling::*[1][name() = name(current())]">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/><xsl:text>" : [</xsl:text>
<xsl:apply-templates select="." mode="obj-content" /><xsl:text>, </xsl:text>
</xsl:when>
<xsl:when test="count(./child::*) > 0 or count(@*) > 0">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : <xsl:apply-templates select="." mode="obj-content" />
<xsl:if test="count(following-sibling::*) > 0">, </xsl:if>
</xsl:when>
<xsl:when test="count(./child::*) = 0">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:apply-templates select="."/><xsl:text>"</xsl:text>
<xsl:if test="count(following-sibling::*) > 0">, </xsl:if>
</xsl:when>
</xsl:choose>
<xsl:text>"Line": "</xsl:text><xsl:value-of select="local-name()"/><xsl:text>"
</xsl:text>
</xsl:template>
<xsl:template match="*" mode="obj-content">
<xsl:text>{</xsl:text>
<xsl:apply-templates select="@*" mode="attr" />
<xsl:if test="count(@*) > 0 and (count(child::*) > 0 or text())">, </xsl:if>
<xsl:apply-templates select="./*" mode="detect" />
<xsl:if test="count(child::*) = 0 and text() and not(@*)">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:value-of select="text()"/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="count(child::*) = 0 and text() and @*">
<xsl:text>"text" : "</xsl:text><xsl:value-of select="text()"/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:text>}</xsl:text>
<xsl:if test="position() < last()">, </xsl:if>
</xsl:template>
<xsl:template match="@*" mode="attr">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:value-of select="."/><xsl:text>"</xsl:text>
<xsl:if test="position() < last()">,</xsl:if>
</xsl:template>
<xsl:template match="node/@TEXT | text()" name="removeBreaks">
<xsl:param name="pText" select="normalize-space(.)"/>
<xsl:choose>
<xsl:when test="not(contains($pText, '
'))"><xsl:copy-of select="$pText"/></xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring-before($pText, '
'), ' ')"/>
<xsl:call-template name="removeBreaks">
<xsl:with-param name="pText" select="substring-after($pText, '
')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>