Question

There are a number of other questions that deal with this area, but I can't make the solutions there work

I have a transform that splits up a Spring bean file containing multiple beans into a set of files, each with one bean

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/beans/bean" xml:space="preserve"> 
            <xsl:result-document href='{translate(normalize-space(./property[@name="name"])," ", "_")}.xml'
            doctype-public="-//SPRING//DTD BEAN//EN"
            doctype-system="http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <xsl:copy-of select="."/>
</beans>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>

This works fine, producing files that start like this:

<!DOCTYPE beans
  PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean class="com.class.mine.Policy" name="bean1">
        <property name="name">

In order that the file looks identical to one originally created with just one bean in it (since the file will be checked into source code management, I want only real differences), I want to change the name="beanN" attribute to name="bean0" in each file. Note that generally the bean tag can contain additional attributes as well as the class and name ones.

Nothing I've tried based on other answers here works. Mostly, I get errors about "Cannot create an attribute node whose parent is a document node" and "Cannot create an attribute node after creating a child of the containing element".

So I'm missing something obvious. What do I need to add to make this extra change?

Update: the problem seems partly to do with the xml:space="preserve". This is presumably causing text nodes to be created. With that removed, I don't get the errors so often but I still can't get the transform right

(and the output has

<beans><bean>

How do I get a linefeed between these tags? I can use indent="yes" to get the output formatted, but I really want to preserve the input format as it was originally, making changes only where I have to)

Update: One of my many attempts. This one runs, but is basically an identity transform. result-doc is commented out to make debugging easier for now. I really don't understand properly how xsl:attribute works so a decent explanation of that might help.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="beans/bean"> 
<!--             <xsl:result-document href='{translate(normalize-space(./property[@name="name"])," /", "_+")}.xml'
            doctype-public="-//SPRING//DTD BEAN//EN"
            doctype-system="http://www.springframework.org/dtd/spring-beans.dtd"
            omit-xml-declaration="no"> -->
<beans>
<xsl:apply-templates select="bean"/>
<xsl:copy-of select="." /> 
</beans>
<!-- </xsl:result-document> -->
</xsl:template>
 <xsl:template match="bean/@*">
      <xsl:copy>
          <xsl:attribute name="name">myvalue</xsl:attribute>
           <xsl:copy-of select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>
Was it helpful?

Solution

If you want specific indentation then you will have to insert the relevant line feeds and spaces yourself:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <xsl:apply-templates select="beans/bean" />
  </xsl:template>

  <xsl:template match="bean"> 
    <xsl:result-document href='{translate(normalize-space(./property[@name="name"])," /", "_+")}.xml'
            doctype-public="-//SPRING//DTD BEAN//EN"
            doctype-system="http://www.springframework.org/dtd/spring-beans.dtd"
            omit-xml-declaration="no">
      <xsl:text>&#10;</xsl:text><!-- newline after the DOCTYPE -->
      <beans>
        <xsl:text>&#10;    </xsl:text><!-- newline and four spaces -->
        <bean>
          <xsl:copy-of select="@*" />
          <xsl:attribute name="name">bean0</xsl:attribute>
          <xsl:copy-of select="node()" />
        </bean>
        <xsl:text>&#10;</xsl:text><!-- newline between </bean> and </beans> -->
      </beans>
    </xsl:result-document>
  </xsl:template>
</xsl:stylesheet>

For the renaming:

        <bean>
          <xsl:copy-of select="@*" />
          <xsl:attribute name="name">bean0</xsl:attribute>
          <xsl:copy-of select="node()" />
        </bean>

first I copy all the attributes (possibly including name) off the original bean tag, then create a(nother) name attribute which will override the one that was copied, then finally copy all the child nodes of the original bean element (which includes elements, comments and text nodes, so will keep the original indentation).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top