简体   繁体   中英

text to xml transforming using xslt

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?

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> 

you can use unparsed-text function from XSLT2.0

For details use W3 specification for this function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM