使用 xslt 将文本转换为 xml

text to xml transforming using xslt

我有一个数据格式如下的文本文件:

FIRSTNAME
Jhon
Rembo

FIRSTNAME
James
KARL

LASTNAME
PAUL
SAM
BOND

我正在尝试使用 XSLT 2.0

将其转换为以下 XML 格式
<?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>

如何获得 XML 结果的任何提示或示例。

编辑:

我已尝试使用以下 java 代码:

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");

和 XSLT 文件:

<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>

编译错误如下:

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)

有什么方法可以将输入作为 txt 文件从 java class 传递?

您可以使用 XSLT2.0 中的未解析文本函数

For details use W3 specification for this function

先把线转成节点:

<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>

然后将它们分组:

<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> 

为了完整起见,XSLT 3.0 将其减少为:

<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>