There are many questions about how to remove duplicate elements when you can group those elements by a certain attribute or value, however, in my case the attributes are being dynamically generated in the XSLT already and I don't want to have to program in every attribute for every element to use as a grouping key.
How do you remove duplicate elements without knowing in advance their attributes? So far, I've tried using generate-id() on each element and grouping by that, but the problem is generate-id isn't generating the same ID for elements with the same attributes:
<xsl:template match="root">
<xsl:variable name="tempIds">
<xsl:for-each select="./*>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="tempID">
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<xsl:for-each-group select="$tempIds" group-by="#tempID">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:template>
Test data:
<root>
<child1>
<etc/>
</child1>
<dynamicElement1 a="2" b="3"/>
<dynamicElement2 c="3" d="4"/>
<dynamicElement2 c="3" d="5"/>
<dynamicElement1 a="2" b="3"/>
</root>
With the end result being only one of the two dynamicElement1 elements remaining:
<root>
<child1>
<etc/>
</child1>
<dynamicElement1 a="2" b="3"/>
<dynamicElement2 c="3" d="4"/>
<dynamicElement2 c="3" d="5"/>
</root>
In XSLT 3 as shown in https://xsltfiddle.liberty-development.net/pPqsHTi you can use a composite key of all attributes with e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="#*">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that technically attributes are not ordered so it might be safer to group by a sort of the attributes by node-name() or similar, as done with XSLT 3 without higher-order functions in https://xsltfiddle.liberty-development.net/pPqsHTi/2
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mf="http://example.com/mf"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:function name="mf:node-sort" as="node()*">
<xsl:param name="input-nodes" as="node()*"/>
<xsl:perform-sort select="$input-nodes">
<xsl:sort select="namespace-uri()"/>
<xsl:sort select="local-name()"/>
</xsl:perform-sort>
</xsl:function>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="mf:node-sort(#*)">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
or as you could do with Saxon EE simply with
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="sort(#*, (), function($att) { namespace-uri($att), local-name($att) })">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/*[#a= following-sibling::*/#a]|root/*[#c= following-sibling::*/#c and #d= following-sibling::*/#d]"/>
You may try this
Related
I have a XML file where elements B are inside elements A and I want to move them up. From:
<?xml version="1.0" encoding="utf-8"?>
<root>
<A>
<C>Text</C>
Text again
More text
<D>Other text</D>
<B>Text again</B>
<C>No</C>
<D>May be</D>
<B>What?</B>
</A>
<A>
Something
<B>Nothing</B>
<D>Again</D>
<B>Content</B>
End
</A>
</root>
I would like to have:
<?xml version="1.0" encoding="utf-8"?>
<root>
<A>
<C>Text</C>
Text again
More text
<D>Other text</D>
</A>
<B>Text again</B>
<A>
<C>No</C>
<D>May be</D>
</A>
<B>What?</B>
<A>
Something
</A>
<B>Nothing</B>
<A>
<D>Again</D>
</A>
<B>Content</B>
<A>
End
</A>
</root>
The closest XSLT program I have is this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A">
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="name()='B'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="A">
<xsl:apply-templates select="."/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
It has two problems: it ignores text nodes (this is probably just a matter of adding |text() to the select="*") but, more important, it creates a element for each node while I would like them to stay together under one . For instance, the above stylesheet makes:
<A><C>No</C></A>
<A><D>May be</D></A>
where I want:
<A><C>No</C>
<D>May be</D></A>
In my XML files, are always direct children of , and there is no or nesting.
The main use case is producing HTML where UL and OL cannot be inside a P.
This question is related but not identical to xslt flattening out child elements in a DocBook para element (and may be also to Flatten xml hierarchy using XSLT
)
As I said in the comment to your question, this is not about moving elements up in hierarchy. It is about grouping nodes, and creating a new parent A element for each group determined by the dividing B element.
In XSLT 1.0 this can be achieved using a so-called sibling recursion:
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="/root">
<xsl:copy>
<xsl:apply-templates select="A"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A">
<xsl:copy>
<xsl:apply-templates select="node()[1][not(self::B)]" mode="sibling"/>
</xsl:copy>
<xsl:apply-templates select="B[1]" mode="sibling"/>
</xsl:template>
<xsl:template match="node()" mode="sibling">
<xsl:copy-of select="." />
<xsl:apply-templates select="following-sibling::node()[1][not(self::B)]" mode="sibling"/>
</xsl:template>
<xsl:template match="B" mode="sibling">
<xsl:copy-of select="." />
<xsl:if test="following-sibling::node()[normalize-space()]">
<A>
<xsl:apply-templates select="following-sibling::node()[1][not(self::B)]" mode="sibling"/>
</A>
<xsl:apply-templates select="following-sibling::B[1]" mode="sibling"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
An XSLT-1.0 solution - which is quite ugly - is the following. The output is as desired, but only for this simple MCVE. A general solution would be far more complicated as #michael.hor257k mentioned in the comments. Without more data it is unlikely to create a better solution in XSLT-1.0. Solutions for XSLT-2.0 and above may simplify this.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="A">
<xsl:if test="normalize-space(text()[1])">
<A>
<xsl:copy-of select="text()[1]" />
</A>
</xsl:if>
<xsl:if test="preceding::*">
<xsl:copy-of select="B[1]" />
</xsl:if>
<A>
<xsl:copy-of select="C[1] | C[1]/following-sibling::text()[1] | D[1]" />
</A>
<xsl:if test="not(preceding::*)">
<xsl:copy-of select="B[1]" />
</xsl:if>
<A>
<xsl:copy-of select="C[2] | C[2]/following-sibling::text()[1]" />
<xsl:if test="D[2]">
<xsl:copy-of select="D[2]" />
</xsl:if>
</A>
<xsl:copy-of select="B[2]" />
<xsl:if test="normalize-space(text()[last()])">
<A>
<xsl:copy-of select="text()[last()]" />
</A>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Concerning the situation of
<A><C>No</C></A>
<A><D>May be</D></A>
It is handled appropriately in the above code. So its output is
<A>
<C>No</C>
<D>May be</D>
</A>
Easy in XSLT 2 or 3 with group-adjacent=". instance of element(B)" or group-adjacent="boolean(self::B)", here is an XSLT 3 example (XSLT 3 is supported by Saxon 9.8 or 9.9 on Java and .NET (https://sourceforge.net/projects/saxon/files/Saxon-HE/) and by Altova since 2017 releases):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="A">
<xsl:for-each-group select="node()" group-adjacent=". instance of element(B)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy select="..">
<xsl:apply-templates select="current-group()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gWmuiKv
In XSLT 2 you need to spell out the <xsl:mode on-no-match="shallow-copy"/> as the identity transformation template and use xsl:element instead xsl:copy:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="A">
<xsl:for-each-group select="node()" group-adjacent=". instance of element(B)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name(..)}" namespace="{namespace-uri(..)}">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
http://xsltransform.hikmatu.com/pPqsHT2
With XSLT 2.0, I am trying to create a list of relations between all children of given elements, in a document such as:
<doc>
<part1>
<name>John</name>
<name>Paul</name>
<name>George</name>
<name>Ringo</name>
<place>Liverpool</place>
</part1>
<part2>
<name>Romeo</name>
<name>Romeo</name>
<name>Juliet</name>
<fam>Montague</fam>
<fam>Capulet</fam>
</part2>
</doc>
The result I would like to obtain, ideally by conflating and weighing the identical relations, would be (in whatever order) something like:
<doc>
<part1>
<rel><name>John</name><name>Paul</name></rel>
<rel><name>John</name><name>George</name></rel>
<rel><name>John</name><name>Ringo</name></rel>
<rel><name>Paul</name><name>George</name></rel>
<rel><name>Paul</name><name>Ringo</name></rel>
<rel><name>George</name><name>Ringo</name></rel>
<rel><name>John</name><place>Liverpool</place></rel>
<rel><name>Paul</name><place>Liverpool</place></rel>
<rel><name>George</name><place>Liverpool</place></rel>
<rel><name>Ringo</name><place>Liverpool</place></rel>
</part1>
<part2>
<rel weight="2"><name>Romeo</name><name>Juliet</name></rel>
<rel weight="2"><name>Romeo</name><fam>Montague</fam></rel>
<rel weight="2"><name>Romeo</name><fam>Capulet</fam></rel>
<rel><name>Juliet</name><fam>Montague</fam></rel>
<rel><name>Juliet</name><fam>Capulet</fam></rel>
<rel><fam>Montague</fam><fam>Capulet</fam></rel>
</part2>
</doc>
—but I'm not sure how to proceed. Many thanks in advance for your help.
You still haven't explained the logic that needs to be applied here, so this is based largely on a guess:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc/*">
<!-- first pass-->
<xsl:variable name="unique-items">
<xsl:for-each-group select="*" group-by="concat(name(), '|', .)">
<item name="{name()}" count="{count(current-group())}" value="{.}"/>
</xsl:for-each-group>
</xsl:variable>
<!-- output -->
<xsl:copy>
<xsl:for-each select="$unique-items/item">
<xsl:variable name="left" select="."/>
<xsl:for-each select="following-sibling::item">
<xsl:variable name="weight" select="$left/#count * #count" />
<rel>
<xsl:if test="$weight gt 1">
<xsl:attribute name="weight" select="$weight"/>
</xsl:if>
<xsl:apply-templates select="$left | ." />
</rel>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:element name="{#name}">
<xsl:value-of select="#value"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The idea here is to remove duplicates in the first pass, then enumerate all combinations in the second (final) pass. The weight is computed by multiplying the number of occurrences of each member of a combination pair and shown only when it exceeds 1.
At least the combinatoric part of your problem could be solved with the following XSLT script. It does not solve the elimination of duplicates, but that could possibly be done in a second transformation.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- standard copy template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="doc/*">
<xsl:copy>
<xsl:variable name="l" select="./*"/>
<xsl:for-each select="$l">
<xsl:variable name="a" select="."/>
<xsl:variable name="posa" select="position()"/>
<xsl:variable name="namea" select="name()"/>
<xsl:for-each select="$l">
<xsl:if test="position() > $posa and (. != $a or name() != $namea)">
<rel>
<xsl:copy-of select="$a"/>
<xsl:copy-of select="."/>
</rel>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to the first part of your example, this produces:
<part1>
<rel><name>John</name><name>Paul</name></rel>
<rel><name>John</name><name>George</name></rel>
<rel><name>John</name><name>Ringo</name></rel>
<rel><name>John</name><place>Liverpool</place></rel>
<rel><name>Paul</name><name>George</name></rel>
<rel><name>Paul</name><name>Ringo</name></rel>
<rel><name>Paul</name><place>Liverpool</place></rel>
<rel><name>George</name><name>Ringo</name></rel>
<rel><name>George</name><place>Liverpool</place></rel>
<rel><name>Ringo</name><place>Liverpool</place></rel>
</part1>
Which seems about correct. If have no idea if the duplicate elimination (or weighting, as you call it) could be done in the same transformation.
Could anyone help me with an XSLT to convert an XSD from Venetian Blind to Russian Doll design? I read an article on Stack Overflow about the reverse: Russian doll to Venetian blind xsl transformation
With a lot of help from a colleague, I finally got an answer. It may not be elegant, but it meets my immediate needs, here it is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
exclude-result-prefixes='exsl'
version="2.0"
xmlns:com="http://canaldigital.com/tsi/XSD/V5.00"
xmlns:exsl="http://exslt.org/common"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="xsd:complexType">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template name="complexTypeElemEmbedded">
<xsl:param name="typeName"></xsl:param>
<xsl:variable name="typeNameNoNS" select="substring-after($typeName, ':')" />
<xsd:complexType>
<xsl:apply-templates select="//xsd:complexType[#name=$typeNameNoNS]/node()"></xsl:apply-templates>
</xsd:complexType>
</xsl:template>
<xsl:template match="xsd:element[#type]">
<xsl:choose>
<!-- All simple types have a name ending in the literal 'Type' -->
<xsl:when test="(ends-with(#type, 'Type'))">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:when>
<!-- this picks up the global complex types -->
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="#*[(name()!='type')]"/>
<xsl:call-template name="complexTypeElemEmbedded">
<xsl:with-param name="typeName" select="#type"/>
</xsl:call-template>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I am getting stuck at a point where I need to remove an element from the input XML:
<message
xmlns="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<m_control>
<control_timestamp>2013-06-06T14:55:37</control_timestamp>
<initiator_id>ASL</initiator_id>
</m_control>
<m_content>
<b_control>
<quote_type>Single Company</quote_type>
<quote_or_print>Quote And Print</quote_or_print>
<generic_quote_ind>Yes</generic_quote_ind>
<tpsdata>
<tps_quote_type>Comparison</tps_quote_type>
</tpsdata>
</b_control>
<application>
<product>
<tpsdata>
<service_type>QuickQuote</service_type>
<quote_type>Standard</quote_type>
</tpsdata>
</product>
</application>
</m_content>
</message>
if <tps_quote_type> is 'Comparison' then change the value of <quote_type> to 'Comparison' and the <tpsdata> field should be removed. The output should look like below.
<message
xmlns="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<m_control>
<control_timestamp>2013-06-06T14:55:37</control_timestamp>
<initiator_id>ASL</initiator_id>
</m_control>
<m_content>
<b_control>
<quote_type>Comparison</quote_type>
<quote_or_print>Quote And Print</quote_or_print>
<generic_quote_ind>Yes</generic_quote_ind>
</b_control>
<application>
<product>
<tpsdata>
<service_type>QuickQuote</service_type>
<quote_type>Standard</quote_type>
</tpsdata>
</product>
</application>
</m_content>
</message>
So far I have tried this XSLT, but I don't know how to remove <tpsdata> field from the output. Could anyone help me in this?
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="dp"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<!-- identity with closing tags -->
<xsl:element name="{name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:variable name="quoteType">
<xsl:value-of select="/*[namespace-uri()='http://www.origoservices.com' and local- name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name() ='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='quote_type']"/>
</xsl:variable>
<xsl:variable name="tpsQuoteType">
<xsl:value-of select="/*[namespace-uri()='http://www.origoservices.com' and local-name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name()='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='tpsdata']/*[namespace-uri()='http://www.origoservices.com' and local-name()='tps_quote_type']"/>
</xsl:variable>
<xsl:template match="/*[namespace-uri()='http://www.origoservices.com' and local-name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name()='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='quote_type']">
<xsl:choose>
<xsl:when test="$tpsQuoteType = 'Comparison' ">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:text>Comparison</xsl:text>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*|comment()|processing-instruction()">
<xsl:copy>
<xsl:copy-of select="#*|namespace::*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Maybe you noticed that your handling of those elements with a namespace is a little painful. Just add the http://www.origoservices.com namespace to your XSLT and the pain goes away.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:o="http://www.origoservices.com"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="dp"
exclude-result-prefixes="fn date"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="o:b_control/o:quote_type[../o:tpsdata/o:tps_quote_type = 'Comparison']">
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:text>Comparison</xsl:text>
</xsl:copy>
</xsl:template>
<xsl:template match="o:tpsdata[o:tps_quote_type = 'Comparison']" />
</xsl:stylesheet>
Notes
Most of your "plumbing" is not necessary.
Template match expressions don't need to be a full path.
Use match expressions rather than <xsl:choose> to pinpoint elements you want to change.
Start with a basic identity template, overriding it as needed with more specific templates. This makes your live much easier than starting with a modified identity template.
Use empty templates to remove specific elements.
<xsl:stylesheet version="1.0" extension-element-prefixes="dp" exclude-result-prefixes="dp regexp fn dpconfig" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" xmlns:dpconfig="http://www.datapower.com/param/config" xmlns:dpfunc="http://www.datapower.com/extensions/functions" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:regexp="http://exslt.org/regular-expressions" >
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name()='tpsdata']/*[local-name()='quote_type']">
<xsl:message dp:priority="debug"> Found quote_type </xsl:message>
<xsl:variable name = "First">
<xsl:value-of select="/*[local-name()='message']/*[local-name()='m_content']/*[local-name()='b_control']/*[local-name()='tpsdata']/*[local-name()='tps_quote_type']/text()"/>
</xsl:variable>
<xsl:variable name = "Second">
<xsl:value-of select = "."/>
</xsl:variable>
<xsl:message dp:priority="debug"> Second:<xsl:value-of select = "$Second"/></xsl:message>
<xsl:message dp:priority="debug"> First: <xsl:value-of select = "$First"/> </xsl:message>
<xsl:choose>
<xsl:when test="$Second = $First">
<xsl:message dp:priority="debug"> Stand and Comp are same </xsl:message>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:message dp:priority="debug"> Stand and Comp are different </xsl:message>
<xsl:copy>
<xsl:value-of select="regexp:replace(*[local-name()='quote_type'],'','',$First)"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*[local-name()='b_control']/*[local-name()='tpsdata']"/>
</xsl:stylesheet>
i'm working the first time with xslt and i really don't understand why this xsl don't copy attributes from the source xml. Perhaps someone can give me a hint??
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="rpl" select="document('ParamInvoice.xml')"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="* | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="vInvoiceElement" select="$rpl/StoraInvoice/*[name()=name(current())]"/>
<xsl:copy>
<xsl:if test="$vInvoiceElement/Attribute">
<xsl:call-template name="AttributeErzeugen">
<xsl:with-param name="pAttr" select="$vInvoiceElement/Attribute"/>
</xsl:call-template>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template name="AttributeErzeugen">
<xsl:param name="pAttr"/>
<xsl:for-each select="$pAttr">
<xsl:attribute name="{#name}"><xsl:value-of select="."/></xsl:attribute>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Instead of <xsl:copy>, you should use <xsl:copy-of>. The difference between both is that copy copies the element only (without attributes and child elements) and copy-of copies the entire elements (attributes, childs, etc).
Check http://www.w3schools.com/xsl/xsl_w3celementref.asp