Reputation: 53
I'd like to convert Kodi-compatible xml to Xtreamer-compatible xml. The input looks like this:
<?xml version="1.0" encoding="utf-8"?>
<movie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<id>something</id>
<title>something</title>
<originaltitle>something</originaltitle>
...and so on... several unknown nodes
<actor>
<name>Name1</name>
<role>Role1</role>
<order>0</order>
</actor>
<actor>
<name>Name2</name>
<role>Role2</role>
<order>1</order>
</actor>
<actor>
<name>Name3</name>
<role>Role3</role>
<order>2</order>
</actor>
...several other unknown nodes...
</movie>
What I'd like to have is:
<?xml version="1.0" encoding="utf-8"?>
<movie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<id>something</id>
<title>something</title>
<originaltitle>something</originaltitle>
...and so on... several unknown nodes
<actor>
<name>Name1</name>
<name>Name2</name>
<name>Name3</name>
</actor>
...several other unknown nodes...
</movie>
...so just drop every child item of actor besides name and put all the names into one common actor tag. The rest of the document should stay unchanged.
What I tried is:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/REC-html40">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/movie">
<actor>
<xsl:for-each select="actor">
<xsl:apply-templates select="name"/>
</xsl:for-each>
</actor>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
What I get is:
<?xml version="1.0"?>
<actor xmlns="http://www.w3.org/TR/REC-html40"><name xmlns="">Name1</name><name xmlns="">Name2</name><name xmlns="">Name3</name></actor>
<id>something</id>
<title>something</title>
<originaltitle>something</originaltitle>
...and so on... several unknown nodes
<actor>
<name>Name1</name>
<role>Role1</role>
<order>0</order>
</actor>
<actor>
<name>Name2</name>
<role>Role2</role>
<order>1</order>
</actor>
<actor>
<name>Name3</name>
<role>Role3</role>
<order>2</order>
</actor>
...several other unknown nodes...
Some things don't work work like wanted:
Any help would be appreciated.
Upvotes: 1
Views: 171
Reputation: 116959
The problem with your template ;
<xsl:template match="/movie">
<actor>
<xsl:for-each select="actor">
<xsl:apply-templates select="name"/>
</xsl:for-each>
</actor>
<xsl:apply-templates/>
</xsl:template>
is that:
movie
node; and actor
children which are also handled separately.What you should have done is:
<xsl:template match="/movie">
<xsl:copy>
<actor>
<xsl:apply-templates select="actor/name"/>
</actor>
<xsl:apply-templates select="*[not(self::actor)]"/>
</xsl:copy>
</xsl:template>
Or, if you really must maintain the position of actor
among its siblings (why is this important?):
<xsl:template match="/movie">
<xsl:copy>
<xsl:apply-templates select="actor[1]/preceding-sibling::*"/>
<actor>
<xsl:apply-templates select="actor/name"/>
</actor>
<xsl:apply-templates select="actor[last()]/following-sibling::*"/>
</xsl:copy>
</xsl:template>
• has no line breaks
I cannot reproduce this problem using your code, but you should have these two at the top level of your stylesheet:
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
NOTE:
As I already mentioned in my comment on your question, this assumes the output XML does NOT need to place its nodes in a namespace - otherwise there's a lot more work that needs to be done.
Upvotes: 1
Reputation: 696
I have come up with this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="actor[1]">
<xsl:copy>
<xsl:copy-of select="../actor/name" />
</xsl:copy>
</xsl:template>
<xsl:template match="actor" />
</xsl:stylesheet>
Instead of using the movie element, I transform the actors. This prevents the movie tag from disappearing, and it will keep the actors in place.
There are two rules for actor, Only the first element will actually select all the names. The other will just remain blank.
The line breaks are still not correct though. But I think it's a bit weird you are so focused on line breaks, as they do not matter in XML. But perhaps you want it so it is more readable.
Upvotes: 1