0
votes

I want to transform a XML document with XSLT. A node and its childern matched by name and attribute should be nested/moved into a new node.

Transform from

<v:data name="Custom">
    <valueA>bla</valueA>
    <valueB>bla</valueB>
    <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>        
    </valueC>
</v:data>

to

<v:container type="static">
    <!-- origin node -->
    <v:data name="Custom">
        <valueA>bla</valueA>
        <valueB>bla</valueB>
        <valueC>
            <valueA>bla</valueA>
            <valueB>bla</valueB>        
        </valueC>
    </v:data>
</v:container>

But my XSLT doesn't work well. Do you have a hint for me, what is wrong with the XSLT file?

Thank you very much

Andreas

My XSLT

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v="http://acme.com/schema.xsd" 
xmlns:d="http://acme.com/data.xsd" 
>

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="v:data/@name[.='Custom']"> 
    <xsl:element name="v:container">
        <xsl:attribute name="type">static</xsl:attribute>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()" />
            </xsl:copy>
    </xsl:element> 
</xsl:template>

</xsl:stylesheet>

The output:

<?xml version="1.0" encoding="UTF-8"?>
<datamodel xmlns:v="http://acme.com/schema.xsd" xmlns:d="http://acme.com/data.xsd">

<v:data> <!-- should be under v:container -->
  <v:container type="static" name="Custom"/> <!-- attribute name should be by v:data -->
  <valueA>bla</valueA> <!-- children should be under v:data -->
  <valueB>bla</valueB>
  <valueC>
    <valueA>bla</valueA>
    <valueB>bla</valueB>
  </valueC>
</v:data>

<v:data name="Default"> <!-- okay: is untouched -->
  <valueA>bla</valueA>
  <valueB>bla</valueB>
  <valueC>
    <valueA>bla</valueA>
    <valueB>bla</valueB>
  </valueC>
</v:data>
</datamodel>

My source XML file

<?xml version="1.0" encoding="UTF-8"?>
<datamodel 
 xmlns:v="http://acme.com/schema.xsd" 
 xmlns:d="http://acme.com/data.xsd" 
>

<v:data name="Custom">
    <valueA>bla</valueA>
    <valueB>bla</valueB>
    <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>        
    </valueC>
</v:data>

<v:data name="Default">
    <valueA>bla</valueA>
    <valueB>bla</valueB>
    <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>        
    </valueC>    
</v:data>

</datamodel>

What I expected at the transformed output I want to nested v:data node and its children into a new node. But only v:data nodes with the attribute name="Custon". After transformation the XML document should look like this

<?xml version="1.0" encoding="UTF-8"?>
<datamodel 
 xmlns:v="http://acme.com/schema.xsd" 
 xmlns:d="http://acme.com/data.xsd" 
>

<v:container type="static"> <!-- changed -->
    <v:data name="Custom">
        <valueA>bla</valueA>
        <valueB>bla</valueB>
        <valueC>
            <valueA>bla</valueA>
            <valueB>bla</valueB>        
        </valueC>
    </v:data>
</v:container>

<v:data name="Default"> <!-- unchanged -->
    <valueA>bla</valueA>
    <valueB>bla</valueB>
    <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>        
    </valueC>    
</v:data>

</datamodel>

Match without attribute If I remove the attribute selector from the template in the XSLT. It will be work - but now very node is transformed.

<?xml version="1.0" encoding="UTF-8"?>
<datamodel xmlns:v="http://acme.com/schema.xsd" xmlns:d="http://acme.com/data.xsd">
  
  <v:container type="static"> <!-- as I expected -->
    <v:data name="Custom">
      <valueA>bla</valueA>
      <valueB>bla</valueB>
      <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>
      </valueC>
    </v:data>
  </v:container>

  <v:container type="static"> <!-- but all v:data nodes are moved -->
    <v:data name="Default">
      <valueA>bla</valueA>
      <valueB>bla</valueB>
      <valueC>
        <valueA>bla</valueA>
        <valueB>bla</valueB>
      </valueC>
    </v:data>
  </v:container>
</datamodel>
1

1 Answers

1
votes

Your template matches the name attribute instead of the v:data element. Try it this way:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v="http://acme.com/schema.xsd" 
xmlns:d="http://acme.com/data.xsd" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="v:data[@name='Custom']">
    <v:container type="static">
        <xsl:copy-of select="."/>
    </v:container>
</xsl:template>

</xsl:stylesheet>