0
votes

So i'm new to xslt, using it for 2 weeks and now stuck with a problem of copying namespaces and attributes form one node to another. I need to copy namespaces and attributes to another node, remove root node and remove some nodes that are not in new node. The second part removing node can be done in other transformation if it's more easy as i think that should be.

Here is input file:

<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1">

<mode>
<node0>0</node0>

<node1 attribute2="some2"> 
    <child1 name="a" id="1"/>
    <child2 name="b" id="2"/>
</node1>

</mode>

<extra1 id="1"/>
<extra2 id="3"/>

<xmi:XMI>

My needed output:

<?xml version="1.0" encoding="UTF-8"?>

<node1 xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1" attribute2="some2" > 
    <child1 name="a" id="1"/>
    <child2 name="b" id="2"/>
</node1>
<extra1 id="1"/>

Probably later will need to keep xmi:XMI node just remove other nodes except node1 and extra1, but think this xsl with modification will help:

<xsl:stylesheet 
xmlns:xls="http://www.w3.org/1999/XSL/Transform" 
xmlns:xmi="http://www.omg.org/spec/XMI/20110701"
 version="2.0">
 <xsl:strip-space elements="*"/> 
<xsl:output indent="yes" method="xml"/>        
 <xsl:template match="@*|node()"> 
<xsl:copy> 
<xsl:apply-templates select="@*|node()"/> 
</xsl:copy> 
</xsl:template> 
<xsl:template match="node"> 
<xsl:apply-templates select="node()"/>
 </xsl:template>
</xsl:stylesheet>

I have no ideas right now how to accomplish this. Any help appreciated.

2
Are you sure you want a fragment without root element as the result? It is possible but unusual so let's confirm that first. And I don't consider the posted sample namespace well-formed XML as the root element has the prefix xmi but no namespace declaration for that prefix so it is hard to tell what you want to achieve.Martin Honnen
Sorry my bad, missed xmi namespace. Yes i now that it's unusual to remove root node, but for this task i need it. Probably will need a xslt transformation that keeps xmi:XMI node and removes other nodes except node1 and extra1, but think simple xsl with modification will help (edited to main post).TerTer
And is there any difference if node is like <node1 .../> and using namespace <namespace1:node1 ...> in extracting that node from xml file?TerTer

2 Answers

1
votes

Here is a sample XSLT 2.0 stylesheet, the main work is not copying namespaces (as that is done by default), the main work is stripping namespaces from extra1 (and potential descendants), I do that with a different mode:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701"
  exclude-result-prefixes="namespace1 xmi">

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="/">
  <xsl:apply-templates select="xmi:XMI/mode/node1"/>
  <xsl:apply-templates select="xmi:XMI/extra1" mode="strip-namespaces"/>
</xsl:template>

<xsl:template match="node1">
  <xsl:copy>
    <xsl:apply-templates select="@*, /*/@*, node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()" mode="strip-namespaces">
  <xsl:element name="{local-name()}">
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates mode="strip-namespaces"/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

With the input being

<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1">

<mode>
<node0>0</node0>

<node1 attribute2="some2"> 
    <child1 name="a" id="1"/>
    <child2 name="b" id="2"/>
</node1>

</mode>

<extra1 id="1"/>
<extra2 id="3"/>

</xmi:XMI>

the output with Saxon 9.4 is

<?xml version="1.0" encoding="UTF-8"?><node1 xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute2="some2" attribute1="some1">
    <child1 name="a" id="1"/>
    <child2 name="b" id="2"/>
</node1><extra1 id="1"/>
0
votes

that script worked thanks. But today my task changed a bit :( Sorry that first question was not final requirements :(

Now i need to do similar just that:

1) Node can be with namespace and i do not now exact position of node, can be namespace1:mode/node0/namespace1:parm, but can namespace1:mode/node0/../namespace1:parm or namespace1:mode/node0/../element or similar but need to find the node by type and name, where namespace1:type="type1" and name="givenName"

2) It can be that different nodes need to become the root node, from example namespace1:parm or element, but must have tag namespace1:parm everytime. For first i need to not remove xmi node and no need to merge attributes if there are used nodes .

3) Namespace from can differ every time, don't now how to make this work. Need to remove unused tags.

4) Probably will need another transformation, but when there is just xmi:XMI and namespace1:parm formated tag with no extar tags in xmi:XMI tag, need to merge xmi:XMI with namespace1:parm and retain all attributes and namespaces.

Input:

<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1" xmlns:M="mOptions" xmlns:N="nOptions">

 <namespace1:mode name="Main">
 <node0>0</node0>

<namespace1:parm name="node1" attribute2="some2" namespace1:type="type1"> 
    <child1 name="a" id="1"/>
    <child2 name="b" id="2"/>
</namespace1:parm>

<element name="node2" attribute2="some3" namespace1:type="type2"> 
    <child6 name="a6" id="6"/>
    <child7 name="b7" id="7"/>
</element>

<node id="55"/>

</namespace1:mode>

<M:extra1 id="1"/>
<M:extra2 id="2"/>
<M:extra6 id="6"/>
<M:extra7 id="7"/>

</xmi:XMI>

First posibility i need similar to last time, need to find everything with namespaces. Tried to modifie the xsl, with no success. Needed output: when namespace1:type="type1"

<?xml version="1.0" encoding="UTF-8"?>

<namespace1:parm name="node1" attribute2="some2" namespace1:type="type1"> 
        <child1 name="a" id="1"/>
        <child2 name="b" id="2"/>
</namespace1:parm>

<M:extra1 id="1"/>
<M:extra2 id="2"/>

when namespace1:type="type2"

<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1" xmlns:M="mOptions" xmlns:N="nOptions">

<namespace1:parm name="node2" attribute2="some3" namespace1:type="type2"> 
        <child6 name="a6" id="6"/>
    <child7 name="b7" id="7"/>
</namespace1:parm>

<M:extra6 id="6"/>
<M:extra7 id="7"/>
</xmi:XMI>

and if:

<namespace1:parm name="node2" attribute2="some3" namespace1:type="type2"> 
        <child6 name="a6" id="6"/>
    <child7 name="b7" id="7"/>
</namespace1:parm>
</xmi:XMI> 

then need

<?xml version="1.0" encoding="UTF-8"?>  
<namespace1:parm name="node2" attribute2="some3" namespace1:type="type2"xmlns:namespace1="http://namespace" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" attribute1="some1" xmlns:M="mOptions" xmlns:N="nOptions"> 
        <child6 name="a6" id="6"/>
    <child7 name="b7" id="7"/>
</namespace1:parm>

Tried:

       <xsl:template match="*">
    <xsl:copy>
        <xsl:for-each select="@*">
            <xsl:attribute name="{name(.)}">
                <xsl:value-of select="."/>
            </xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates select="xmi:XMI|*[@namespace1:type='type1']"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="xmi:XMI|*[@namespace1:type='type1']">
    <xsl:copy>
        <xsl:for-each select="@*">
            <xsl:attribute name="{name(.)}">
                <xsl:value-of select="."/>
            </xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

But getting:

             <?xml version="1.0" encoding="UTF-8"?>
  <xmi:XMI xmlns:namespace1="http://namespace"
             xmlns:xmi="http://www.omg.org/spec/XMI/20110701"
             xmlns:M="mOptions"
           xmlns:N="nOptions"
           attribute1="some1">some1<namespace1:mode name="Main">
        <namespace1:parm name="node1" attribute2="some2"           namespace1:type="type1">node1some2type1<child1 name="a" id="1"/>
           <child2 name="b" id="2"/>
        </namespace1:parm>
     </namespace1:mode>
     <M:extra1 id="1"/>
       <M:extra2 id="3"/>
     <M:extra6 id="6"/>
     <M:extra7 id="7"/>
     </xmi:XMI>