Reputation: 175
If I have this input file:
<root>
<node id="N1">
<fruit id="small_fruit">
<orange id="1" action="create">
<attribute>
<color>yellow</color>
</attribute>
</orange>
</fruit>
<fruit id="large_fruit" action="create">
<melon id="1" action="destroy">
<attribute>
<color>green</color>
</attribute>
</melon>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<poodle id="1" action="create">
<attribute>
<color>Yellow</color>
</attribute>
</poodle>
<poodle id="1" action="change">
<attribute>
<color>Brown</color>
</attribute>
</poodle>
<terrier id="2" action="destroy">
<attribute>
<color>Blue</color>
</attribute>
</terrier>
</dog>
</node>
</root>
and I need to separate into two files: output1: node_destroy.xml
<root>
<node id="N1">
<fruit id="large_fruit" action="create">
<melon id="1" action="destroy">
<attribute>
<color>green</color>
</attribute>
</melon>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<terrier id="2" action="destroy">
<attribute>
<color>Blue</color>
</attribute>
</terrier>
</dog>
</node>
</root>
output2: node_other_than_destroy.xml
<root>
<node id="N1">
<fruit id="small_fruit">
<orange id="1" action="create">
<attribute>
<color>yellow</color>
</attribute>
</orange>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<poodle id="1" action="create">
<attribute>
<color>Yellow</color>
</attribute>
</poodle>
<poodle id="1" action="change">
<attribute>
<color>Brown</color>
</attribute>
</poodle>
</dog>
</node>
</root>
Basically I need to remove the node with action='destroy' to one file and other node with other action into another file. (the checked action-node is melon, poodle, terrier NOT their parents, i.e. fruit and dog)
Please help me with the transformation file. Thanks very much.
regards, John
Upvotes: 2
Views: 2676
Reputation: 243549
In XSLT 1.0 there isnt a way to create more than one outputs from one execution of a transformation.
Here are two separate XSLT 1.0 transformations:
The first produces only the result with action="destroy
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[not(*/*/@action = 'destroy')]"/>
<xsl:template match="node/*[not(*/@action = 'destroy')]"/>
<xsl:template match="node/*/*[not(@action = 'destroy')]"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<root>
<node id="N1">
<fruit id="small_fruit">
<orange id="1" action="create">
<attribute>
<color>yellow</color>
</attribute>
</orange>
</fruit>
<fruit id="large_fruit" action="create">
<melon id="1" action="destroy">
<attribute>
<color>green</color>
</attribute>
</melon>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<poodle id="1" action="create">
<attribute>
<color>Yellow</color>
</attribute>
</poodle>
<poodle id="1" action="change">
<attribute>
<color>Brown</color>
</attribute>
</poodle>
<terrier id="2" action="destroy">
<attribute>
<color>Blue</color>
</attribute>
</terrier>
</dog>
</node>
</root>
the wanted, correct result is produced:
<root>
<node id="N1">
<fruit id="large_fruit" action="create">
<melon id="1" action="destroy">
<attribute>
<color>green</color>
</attribute>
</melon>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<terrier id="2" action="destroy">
<attribute>
<color>Blue</color>
</attribute>
</terrier>
</dog>
</node>
</root>
The second transformation producess all "non-destroy" content:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[not(*/*/@action[not(. = 'destroy')])]"/>
<xsl:template match="node/*[not(*/@action[not(. = 'destroy')])]"/>
<xsl:template match="node/*/*[@action = 'destroy']"/>
</xsl:stylesheet>
when this transformation is applied on the same XML document (above), the wanted result is produced:
<root>
<node id="N1">
<fruit id="small_fruit">
<orange id="1" action="create">
<attribute>
<color>yellow</color>
</attribute>
</orange>
</fruit>
</node>
<node id="N2">
<dog id="small_dog">
<poodle id="1" action="create">
<attribute>
<color>Yellow</color>
</attribute>
</poodle>
<poodle id="1" action="change">
<attribute>
<color>Brown</color>
</attribute>
</poodle>
</dog>
</node>
</root>
II. XSLT 2.0 Solution -- creating both output files within the same transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*" mode="destroyed non-destroyed">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vResultDestroyed">
<xsl:apply-templates mode="destroyed"/>
</xsl:variable>
<xsl:variable name="vResultNonDestroyed">
<xsl:apply-templates mode="non-destroyed"/>
</xsl:variable>
<xsl:for-each select="1 to 2">
<xsl:result-document
href="file:///c:temp/delete/{'non-'[position()=current()]}destroyed.xml">
<xsl:copy-of select=
"($vResultNonDestroyed, $vResultDestroyed)[position() = current()]"/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template mode="destroyed" match="node[not(*/*/@action = 'destroy')]"/>
<xsl:template mode="destroyed" match="node/*[not(*/@action = 'destroy')]"/>
<xsl:template mode="destroyed" match="node/*/*[not(@action = 'destroy')]"/>
<xsl:template mode="non-destroyed" match="node[not(*/*/@action[not(. = 'destroy')])]"/>
<xsl:template mode="non-destroyed" match="node/*[not(*/@action[not(. = 'destroy')])]"/>
<xsl:template mode="non-destroyed" match="node/*/*[@action = 'destroy']"/>
</xsl:stylesheet>
when this transformation is run with Saxon 9.1.07, the correct output is written to the files:
C:\Program Files\Java\jre6\bin\temp\delete\destroyed.xml
and
C:\Program Files\Java\jre6\bin\temp\delete\non-destroyed.xml
Upvotes: 2
Reputation: 167716
Which XSLT processor do you use? If that is an XSLT 2.0 processor like Saxon 9 or AltovaXML or XmlPrime then you can use the xsl:result-document instruction
. With an XSLT 1.0 processor you will need to check whether the processor supports an extension instruction to create multiple result documents.
So tell us which processor you use, then we can suggest concrete code samples for your input sample and the desired output samples.
[edit] I have prepared an XSLT 2.0 sample:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="action" as="xs:string" select="'destroy'"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:result-document href="node_{$action}.xml">
<xsl:apply-templates/>
</xsl:result-document>
<xsl:result-document href="node_other_than_{$action}.xml">
<xsl:apply-templates mode="other"/>
</xsl:result-document>
</xsl:template>
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@* , node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[*/*[@action = $action]]
| /*/*/*[*[@action = $action]]">
<xsl:next-match/>
</xsl:template>
<xsl:template match="/*/*[not(*/*[@action = $action])]
| /*/*/*[not(*[@action = $action])]
| /*/*/*/*[not(@action = $action)]"/>
<xsl:template match="/*/*[*/*[not(@action = $action)]]
| /*/*/*[*[not(@action = $action)]]" mode="other">
<xsl:next-match/>
</xsl:template>
<xsl:template match="/*/*[not(*/*[not(@action = $action)])]
| /*/*/*[not(*[not(@action = $action)])]
| /*/*/*/*[@action = $action]" mode="other"/>
</xsl:stylesheet>
Upvotes: 2