Hi all,

I want to transform an xml file to another xml file based on the length of innertext in an element.

Here is an example of the file to be transformed:

<?xml version="1.0" encoding="utf-8"?>
<recipe xmnls="">
  <recipeList>
    <recipeType description="Breakfast">
      <recipeInfo>
        <name>Omelet</name>
        <summary>An English Breakfast</summary>
        <ingredients>Eggs,Butter</ingredients>
        <instructions>(1) You will need 2 eggs, 1 tbspn butter,............................................................................................................................................................</instructions>
      </recipeInfo>
    </recipeType>
  </recipeList>
</recipe>

As you notice, the <instructions> node has a lot of text. I want to transform the xml file into the following format:

<?xml version="1.0" encoding="utf-8"?>
<recipe xmnls="">
  <recipeList>
    <recipeType description="Breakfast">
      <recipeInfo>
        <name>Omelet</name>
        <summary>An English Breakfast</summary>
        <ingredients>Eggs,Butter</ingredients>
        <instructions>(1) You will need 2 eggs, 1 tbspn butter,...
                      ............................................
                      ............................................
                      ............................................
                      ............................................
        </instructions>
      </recipeInfo>
    </recipeType>
  </recipeList>
</recipe>

Thanks

So you want to basically add a newline after X number of string characters?

First line = 44 characters
Next Line = 44 Characters
Etc
Last Line = Leftover text < 44

What's the rule that you're using to format that particular text node? Once I know that I'll be happy to help out.

Well this is the rule. The xml file is bound in two ways. It is populated from a textbox as input and its output is displayed in a textblock of fixed width. Without the newline included, the xml file in its default settings would display the output on a single line in the textblock thus surpassing the fixed width. What I am trying to do is to have the xml display a newline after a fixed number of characters such as you indicated. Code is generally written in xaml and partially c# (xaml preferred).

textbox populates xml file (first format)
xml is formatted with newline characters
textblock displays formatted xml (second format).

Hope this clarifies the objective.

Thanks

Edited 5 Years Ago by ibdatx: n/a

Sure thing. Here's a solution. The idea here that the identity transformation runs the show. Once it matches on a "instructions" node, it copies the "instructions" element and then calls the "insertnewline" template.

There are 2 parameters that you feed this template. One is the "textleft" which is the text field you want to seperate out and add newlines too. The "length" is the number of characters that you want to go before you add the newline. In this case, it's the "instructions" node text, and 44.

The call-template itself works recursively. It takes the input string, and checks if it's less than the length specified. If so, then it just spits out the same string. If not, then it divides the string from the first character in the input, down to the nth character, where n is the length you've specified. It then also adds a newline to that string result "&#xa;". From there it calls itself again, this time passing itself new parameters, the length stays the same, but the NEW input string is all characters that are AFTER where you divided the first part. this new smaller string starts the recursion over again. This continues until the resulting string is less than the length specified and stops.

I used your input document to produce the following.

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="xml"/>
	<xsl:strip-space elements="*"/>

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

	<xsl:template match="instructions">
		<xsl:copy>			
			<xsl:call-template name="insertnewline">
				<xsl:with-param name="length" select="44"/>
				<xsl:with-param name="textleft" select="." />
			</xsl:call-template>
		</xsl:copy>
	</xsl:template>

	<xsl:template name="insertnewline">
		<xsl:param name="length" />
		<xsl:param name="textleft"/>
		<xsl:choose>
			<xsl:when test="string-length($textleft) &lt;= $length">
				<xsl:value-of select="$textleft" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="substring($textleft, 1, $length)" />
				<xsl:text>&#xa;</xsl:text>				
				<xsl:call-template name="insertnewline" >
					<xsl:with-param name="length" select="$length" />
					<xsl:with-param name="textleft" select="substring($textleft, $length, string-length($textleft))" />
				</xsl:call-template>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
</xsl:stylesheet>

Output

<recipe>
  <recipeList>
    <recipeType description="Breakfast">
      <recipeInfo>
        <name>Omelet</name>
        <summary>An English Breakfast</summary>
        <ingredients>Eggs,Butter</ingredients>		
        <instructions>(1) You will need 2 eggs, 1 tbspn butter,...
............................................
............................................
............................................
.........................</instructions>
      </recipeInfo>
    </recipeType>
  </recipeList>
</recipe>

If you examine the text of the instructions node, you'll find it has a newline after every 44 characters and the last line is just was is leftover. This wasn't heavily tested, so there could be some bugs, but it gives you the idea.

Edited 5 Years Ago by iceandrews: n/a

Definitely excellent stuff, and prompt response too. Thanks.

This question has already been answered. Start a new discussion instead.