0

I have an text file with below data format:

FIRSTNAME
Jhon
Rembo

FIRSTNAME
James
KARL

LASTNAME
PAUL
SAM
BOND

I am trying to convert it into below XML format using XSLT 2.0

<?xml version="1.0" encoding="UTF-8"?>
<customers>
    <firstnames>
        <firstname>Jhon</firstname>
        <firstname>Rembo</firstname>
    </firstnames>
    <firstnames>
        <firstname>James</firstname>
        <firstname>KARL</firstname>
    </firstnames>
    <lastnames>
        <lastname>PAUL</lastname>
        <lastname>SAM</lastname>
        <lastname>BOND</lastname>       
    </lastnames>    
</customers>

Any hints or example how to achieve XML result.

EDIT:

I have tried with below java code:

final String TXT_PATH = "D:/TXT_one.txt";
final String XSLT_PATH = "D:/XSLT_one.xslt";
final String XML_PATH = "D:/test_xml_result_one.xml";

TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl();
Transformer transformer = tFactory.newTransformer(new StreamSource(new File(XSLT_PATH)));
transformer.transform(new StreamSource(new File(TXT_PATH)), new StreamResult(new File(XML_PATH)));

System.out.println("Output written to text file");

and XSLT file:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:my="my:my" exclude-result-prefixes="ext my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:variable name="lines" as="element()*">
      <xsl:for-each select="tokenize(unparsed-text($input), '\r?\n')">
        <line><xsl:value-of select="."/></line>
      </xsl:for-each>
  </xsl:variable>

  <results>
   <xsl:apply-templates select="$lines/*"/>
  </results>
 </xsl:template>

 <xsl:template match="text()" name="group">
 <xsl:param name="lines" select="."/>
    <xsl:for-each-group select="$lines[normalize-space()]" 
          group-starting-with="*[.=('FIRSTNAME', 'LASTNAME')]">
          <xsl:element name="{lower-case(.)}s">
            <xsl:for-each select="remove(current-group(), 1)">
              <xsl:element name="{lower-case(current-group()[1])}">
                <xsl:value-of select="."/>
              </xsl:element>
            </xsl:for-each>
          </xsl:element>
      </xsl:for-each-group> 
 </xsl:template>

</xsl:stylesheet>

an compilation error getting like:

Error at xsl:for-each on line 9 column 68 of XSLT_one.xslt:
XPST0008: Variable input has not been declared (or its declaration is not in scope)

any way to pass input as txt file from java class?

1
  • XSLT is designed to transform XML input to another XML schema or HTML or text. Why it may be possible to transform text to XML (if using XSLT 2.0), I would look for a more suitable tool. Commented Nov 18, 2015 at 11:30

2 Answers 2

2

First turn the lines into nodes:

<xsl:variable name="lines" as="element()*">
  <xsl:for-each select="tokenize(unparsed-text($input), '\r?\n')">
    <line><xsl:value-of select="."/></line>
  </xsl:for-each>
</xsl:variable>

Then group them:

<xsl:for-each-group select="$lines[normalize-space()]" 
  group-starting-with="*[.=('FIRSTNAME', 'LASTNAME')]">
  <xsl:element name="{lower-case(.)}s">
    <xsl:for-each select="remove(current-group(), 1)">
      <xsl:element name="{lower-case(current-group()[1])}">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:for-each>
  </xsl:element>
</xsl:for-each-group> 

For completeness, this reduces with XSLT 3.0 to:

<xsl:for-each-group 
   select="unparsed-text-lines($input)[normalize-space()]" 
   group-starting-with=".[.=('FIRSTNAME', 'LASTNAME')]">
   <xsl:element name="{lower-case(.)}s">
     <xsl:for-each select="tail(current-group())">
       <xsl:element name="{lower-case(current-group()[1])}">
         <xsl:value-of select="."/>
       </xsl:element>
     </xsl:for-each>
   </xsl:element>
</xsl:for-each-group> 
Sign up to request clarification or add additional context in comments.

3 Comments

thank you for the answer, let me try and get back to you.
question updated, is there any way i can pass input to xslt from java class.
Just declare <xsl:param name="input" as="xs:string"/>, and pass a value to the parameter from Java using transformer.setParameter().
0

you can use unparsed-text function from XSLT2.0

For details use W3 specification for this function

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.