Reputation: 527
I have the following xml code (simplified, the pseudonyms is always present, but Patient could als be an other tag with different content):
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<patient>
<Sexe>V</Sexe>
<yob>1984</yob>
<status>2</status>
</patient>
</Data>
</Record>
I'm looking for an xslt solution so the result looks like:
<Record>
<patient>
<B>e113</B>
<M>lss9</M>
<S>f6rr</S>
<Sexe>V</Sexe>
<yob>1984</yob>
<status>2</status>
</patient>
</Record>
The question would be how I can combine the pseudonyms tag and, in this case the Patient-tag to one record. As mentioned this is a simplified example. The Patient-tag can also be an other tag in the same document. So I need a generic solution that combines whatever tags comes after with the Pseudonyms-tag with the prefix of the tag that follows after (in this example Patient).
I know how to transform <Pseudonym type="B">e113</Pseudonym>
into <B>e113</B>
, but I don't know how to combine the tags in the right way to come to the result in the example.
I hope I could explained well enough what I try to accomplice. Tia.
Edit:
What I didn't mention is that Patient is just one of the many different tags. So a short version would be:
XML
<?xml version="1.0" encoding="UTF-8"?>
<Bestand>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<Patient>
<Sexe>V</Sexe>
<yob>1984</yob>
<status>2</status>
</Patient>
</Data>
</Record>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<SurveyA>
<Item01>1</Item01>
<Item02>4</Item02>
<Item03>8</Item03>
</SurveyA>
</Data>
</Record>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<SurveyB>
<Item01>1</Item01>
<Item02>3</Item02>
<Item03>2</Item03>
</SurveyB>
</Data>
</Record>
</Bestand>
My xsl looks like:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:element name="message">
<xsl:apply-templates select="//Data"/>
</xsl:element>
</xsl:template>
<xsl:template match="Patient|SurveyA|SurveyB">
<xsl:element name="{name()}">
<xsl:element name="B"><xsl:value-of select="//Pseudonyms/Pseudonym[@type='B']" /></xsl:element>
<xsl:element name="M"><xsl:value-of select="//Pseudonyms/Pseudonym[@type='M']" /></xsl:element>
<xsl:element name="S"><xsl:value-of select="//Pseudonyms/Pseudonym[@type='S']" /></xsl:element>
<xsl:copy-of select="node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This results in the next output which is what I want, but I also wonder is there would be a better, more cleaner way.
![Output][1]
[1]: https://i.sstatic.net/1Lcea.png
As said, this works, I have just one problem left, there could be multiple Patient, SurveyA en SurveyB records. When I apply my stylesheet, the whole thing is not sorted. So there can be a Patient record followed by a SurveyA record. This SurveyA record can, in its turn be followed by a Patient record. It would be nice if I could group the specific items. This I haven't been able to accomplice.
Upvotes: 0
Views: 73
Reputation: 52848
Here's an option that similar to forty-two's answer, but takes into account your updated question.
Notes:
Pseudonym
by @type
. If this isn't necessary, just remove the xsl:sort
.Pseudonym
elements. If they are as static as the appear in your question, you can go back to hard coding the elements in and using xsl:value-of
. (You don't need to use xsl:element
though.XML Input (modified slightly to show sorting)
<Bestand>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113a</Pseudonym>
<Pseudonym type="M">lss9a</Pseudonym>
<Pseudonym type="S">f6rra</Pseudonym>
</Pseudonyms>
<Data>
<Patient>
<Sexe>V</Sexe>
<yob>1984</yob>
<status>2</status>
</Patient>
</Data>
</Record>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<SurveyA>
<Item01>1</Item01>
<Item02>4</Item02>
<Item03>8</Item03>
</SurveyA>
</Data>
</Record>
<Record>
<Pseudonyms>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<Patient>
<Sexe>W</Sexe>
<yob>1985</yob>
<status>3</status>
</Patient>
</Data>
</Record>
<Record>
<Pseudonyms>
<Pseudonym type="B">e113</Pseudonym>
<Pseudonym type="M">lss9</Pseudonym>
<Pseudonym type="S">f6rr</Pseudonym>
</Pseudonyms>
<Data>
<SurveyB>
<Item01>1</Item01>
<Item02>3</Item02>
<Item03>2</Item03>
</SurveyB>
</Data>
</Record>
</Bestand>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<message>
<xsl:apply-templates select="Record/Data/*">
<xsl:sort select="local-name()"/>
</xsl:apply-templates>
</message>
</xsl:template>
<xsl:template match="Data/*">
<xsl:copy>
<xsl:apply-templates select="../../Pseudonyms/Pseudonym">
<xsl:sort select="@type"/>
</xsl:apply-templates>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Pseudonym">
<xsl:element name="{@type}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
XML Output
<message>
<Patient>
<B>e113a</B>
<M>lss9a</M>
<S>f6rra</S>
<Sexe>V</Sexe>
<yob>1984</yob>
<status>2</status>
</Patient>
<Patient>
<B>e113</B>
<M>lss9</M>
<S>f6rr</S>
<Sexe>W</Sexe>
<yob>1985</yob>
<status>3</status>
</Patient>
<SurveyA>
<B>e113</B>
<M>lss9</M>
<S>f6rr</S>
<Item01>1</Item01>
<Item02>4</Item02>
<Item03>8</Item03>
</SurveyA>
<SurveyB>
<B>e113</B>
<M>lss9</M>
<S>f6rr</S>
<Item01>1</Item01>
<Item02>3</Item02>
<Item03>2</Item03>
</SurveyB>
</message>
Upvotes: 1
Reputation: 12817
Here's one way of doing it:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Record">
<Record>
<patient>
<xsl:apply-templates select="Pseudonyms/Pseudonym" />
<xsl:apply-templates select="Data/patient/*" />
</patient>
</Record>
</xsl:template>
<xsl:template match="Pseudonym">
<xsl:element name="{@type}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1