Reputation: 61
I have the following XML coming in:
<Record>
<FILE>F1235-01</FILE>
<PERSONID>1234</PERSONID>
<LNAME>Smith</LNAME>
<AGE>54</AGE>
<WEIGHT>158</WEIGHT>
<RACE>White</RACE>
</Record>
<Record>
<FILE>F1237-02</FILE>
<PERSONID>7856</PERSONID>
<LNAME>Hill</LNAME>
<SEX>F</SEX>
<WEIGHT>124</WEIGHT>
</Record>
<Record>
<FILE>F1240-07</FILE>
<PERSONID>5634</PERSONID>
<LNAME>Patel</LNAME>
<HEIGHT>67</HEIGHT>
<HAIR>Black</HAIR>
</Record>
The first three elements in each Record will always be the same, FILE, PERSONID, LNAME. After that, each Record will have different elements, not even the same number of elements- some may have one 1, others may have 50. In order to Database this, I need to get one record for each of the varying elements BUT with the first three identifying elements.
<Record>
<FILE>F1235-01</FILE>
<PERSONID>1234</PERSONID>
<LNAME>Smith</LNAME>
<ATTRIBUTE>AGE</ATTRIBUTE>
<VALUE>54</VALUE>
</Record>
<Record>
<FILE>F1235-01</FILE>
<PERSONID>1234</PERSONID>
<LNAME>Smith</LNAME>
<ATTRIBUTE>WEIGHT</ATTRIBUTE>
<VALUE>158</VALUE>
</Record>
<Record>
<FILE>F1235-01</FILE>
<PERSONID>1234</PERSONID>
<LNAME>Smith</LNAME>
<ATTRIBUTE>RACE</ATTRIBUTE>
<VALUE>White</VALUE>
</Record>
<Record>
<FILE>F1237-02</FILE>
<PERSONID>7856</PERSONID>
<LNAME>Hill</LNAME>
<ATTRIBUTE>SEX</ATTRIBUTE>
<VALUE>F</VALUE>
</Record>
<Record>
<FILE>F1237-02</FILE>
<PERSONID>7856</PERSONID>
<LNAME>Hill</LNAME>
<ATTRIBUTE>WEIGHT</ATTRIBUTE>
<VALUE>124</VALUE>
</Record>
<Record>
<FILE>F1240-07</FILE>
<PERSONID>5634</PERSONID>
<LNAME>Patel</LNAME>
<ATTRIBUTE>HEIGHT</ATTRIBUTE>
<VALUE>67</VALUE>
</Record>
<Record>
<FILE>F1240-07</FILE>
<PERSONID>5634</PERSONID>
<LNAME>Patel</LNAME>
<ATTRIBUTE>HAIR</ATTRIBUTE>
<VALUE>Black</VALUE>
</Record>
I can't come up with any XML which loops through elements after the third, though it seems like it would be simple in theory. Any help would be appreciated.
Upvotes: 0
Views: 257
Reputation: 29052
This is another XSLT-1.0 solution:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" />
<xsl:strip-space elements="*" />
<!-- Identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Record | Record/* | text()">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Record/*[position()>3]">
<Record>
<xsl:copy-of select="../*[3 >= position()]" />
<ATTRIBUTE><xsl:value-of select="local-name()" /></ATTRIBUTE>
<VALUE><xsl:value-of select="." /></VALUE>
</Record>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 117102
How about something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Records">
<xsl:copy>
<xsl:for-each select="Record">
<xsl:variable name="common" select="FILE | PERSONID | LNAME"/>
<xsl:for-each select="*[position() > 3]">
<Record>
<xsl:copy-of select="$common"/>
<ATTRIBUTE>
<xsl:value-of select="name()"/>
</ATTRIBUTE>
<VALUE>
<xsl:value-of select="."/>
</VALUE>
</Record>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that this assumes every Record has at least one additional attribute. And that the input is a well-formed XML, unlike the one in your question - for example, it has a root element named Records
.
Upvotes: 1