xslt 2.0 标记化和分组
xslt 2.0 tokenize and group
我有一个包含以下数据的文本文件:
<t>Heros
Firstname Sean
Lastname Connery
DOB 25-08-1930
Films
Dr.No 1962
Goldfinger 1964
Thunerball 1965
Award
name Academy
time 1
Award
name BAFTA
time 2
Award
name Gloden Globes
time 3</t>
预期输出应如下所示:
<Jamesfilms>
<heros>
<firstName>Sean</firstName>
<lastName>Connery</lastName>
<DOB>25-08-1930</DOB>
</heros>
<films>
<Dr.No>1962</Dr.No>
<Goldfinger>1964</Goldfinger>
<Thunerball>1965</Thunerball>
</films>
<award>
<name>Academy</name>
<times>1</times>
</award>
<award>
<name>BAFTA</name>
<times>2</times>
</award>
<award>
<name>Gloden Globes</name>
<times>3</times>
</award>
</Jamesfilms>
文本文件内容为space分隔键值对,如何划分键值生成XML节点?
编辑: 我已经尝试 回答,并试图解决以下异常:
Error at xsl:for-each on line 10 of transformer.xslt:
XTDE1170: Invalid relative URI: Illegal character in path at index 5:
Java class:
final String TXT_PATH = "E:/tmp/test/input.txt";
final String XSLT_PATH = "E:/tmp/test/txtToXml.xslt";
final String XML_PATH = "E:/tmp/test/test_xml_result.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)));
并修改了 xslt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text(., $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{$tokens[1]}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
你应该不需要分组;你可以只标记化(然后标记化和标记化...)。
这是一个例子。它对元素名称的大小写没有任何作用。您可以在构建 $initData
期间处理这些更改,也可以添加其他模板来处理任何更改。
此外,元素名称必须是有效的 QName。现在样式表终止处理并显示一条消息,但您可以更改其处理方式。
这至少应该让你开始......
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:param name="input-uri" as="xs:string" select="'so.txt'"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{$tokens[1]}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
编辑
您正在传递文本文件作为转换的输入。这就是您必须添加 <t>
元素的原因。
因为您实际上没有 XML 输入,您可以将样式表本身作为输入传递。不会处理任何内容,因为我们只是将模板应用到模板中匹配根 (/
) 的变量。
您还需要使用 transformer.setParameter("input-uri", TXT_PATH);
设置 input-uri
参数。如果您的路径是绝对路径,请务必添加 file:///
协议。
示例...
文本文件
Heros
Firstname Sean
Lastname Connery
DOB 25-08-1930
Films
Dr.No 1962
Goldfinger 1964
Thunerball 1965
Award
name Academy
time 1
Award
name BAFTA
time 2
Award
name Gloden Globes
time 3
Java(你需要更改paths/filenames)
final String TXT_PATH = "file:///C:/tmp/input.txt";
final String XSLT_PATH = "C:/tmp/txt2xml.xsl";
final String XML_PATH = "C:/tmp/test_xml_result.xml";
TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl();
Transformer transformer = tFactory.newTransformer(new StreamSource(new File(XSLT_PATH)));
transformer.setParameter("input-uri", TXT_PATH);
transformer.transform(new StreamSource(new File(XSLT_PATH)),new StreamResult(new File(XML_PATH)));
XSLT 2.0
同上
输出
<Jamesfilms>
<Heros>
<Firstname>Sean</Firstname>
<Lastname>Connery</Lastname>
<DOB>25-08-1930</DOB>
</Heros>
<Films>
<Dr.No>1962</Dr.No>
<Goldfinger>1964</Goldfinger>
<Thunerball>1965</Thunerball>
</Films>
<Award>
<name>Academy</name>
<time>1</time>
</Award>
<Award>
<name>BAFTA</name>
<time>2</time>
</Award>
<Award>
<name>Gloden Globes</name>
<time>3</time>
</Award>
</Jamesfilms>
但是,由于您使用的是 Saxon,因此可以使用 s9api 并指定一个初始模板。这是我将采用的方式,而不是将样式表作为输入传递给转换。
示例...
Java
final String TXT_PATH = "file:///C:/tmp/input.txt";
final String XSLT_PATH = "C:/tmp/txt2xml.xsl";
final String XML_PATH = "C:/tmp/test_xml_result.xml";
Processor processor = new Processor(false);
Serializer serializer = processor.newSerializer();
serializer.setOutputFile(new File(XML_PATH));
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable executable = compiler.compile(new StreamSource(new File(XSLT_PATH)));
XsltTransformer transformer = executable.load();
transformer.setInitialTemplate(new QName("root"));
transformer.setParameter(new QName("input-uri"), new XdmAtomicValue(TXT_PATH));
transformer.setDestination(serializer);
transformer.transform();
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:param name="input-uri" as="xs:string"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{replace($tokens[1],'\s','')}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/" name="root">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
输入和输出是一样的。如果您需要我将 java 导入添加到示例中,请告诉我。
我有一个包含以下数据的文本文件:
<t>Heros
Firstname Sean
Lastname Connery
DOB 25-08-1930
Films
Dr.No 1962
Goldfinger 1964
Thunerball 1965
Award
name Academy
time 1
Award
name BAFTA
time 2
Award
name Gloden Globes
time 3</t>
预期输出应如下所示:
<Jamesfilms>
<heros>
<firstName>Sean</firstName>
<lastName>Connery</lastName>
<DOB>25-08-1930</DOB>
</heros>
<films>
<Dr.No>1962</Dr.No>
<Goldfinger>1964</Goldfinger>
<Thunerball>1965</Thunerball>
</films>
<award>
<name>Academy</name>
<times>1</times>
</award>
<award>
<name>BAFTA</name>
<times>2</times>
</award>
<award>
<name>Gloden Globes</name>
<times>3</times>
</award>
</Jamesfilms>
文本文件内容为space分隔键值对,如何划分键值生成XML节点?
编辑: 我已经尝试
Error at xsl:for-each on line 10 of transformer.xslt:
XTDE1170: Invalid relative URI: Illegal character in path at index 5:
Java class:
final String TXT_PATH = "E:/tmp/test/input.txt";
final String XSLT_PATH = "E:/tmp/test/txtToXml.xslt";
final String XML_PATH = "E:/tmp/test/test_xml_result.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)));
并修改了 xslt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text(., $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{$tokens[1]}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
你应该不需要分组;你可以只标记化(然后标记化和标记化...)。
这是一个例子。它对元素名称的大小写没有任何作用。您可以在构建 $initData
期间处理这些更改,也可以添加其他模板来处理任何更改。
此外,元素名称必须是有效的 QName。现在样式表终止处理并显示一条消息,但您可以更改其处理方式。
这至少应该让你开始......
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:param name="input-uri" as="xs:string" select="'so.txt'"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{$tokens[1]}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
编辑
您正在传递文本文件作为转换的输入。这就是您必须添加 <t>
元素的原因。
因为您实际上没有 XML 输入,您可以将样式表本身作为输入传递。不会处理任何内容,因为我们只是将模板应用到模板中匹配根 (/
) 的变量。
您还需要使用 transformer.setParameter("input-uri", TXT_PATH);
设置 input-uri
参数。如果您的路径是绝对路径,请务必添加 file:///
协议。
示例...
文本文件
Heros
Firstname Sean
Lastname Connery
DOB 25-08-1930
Films
Dr.No 1962
Goldfinger 1964
Thunerball 1965
Award
name Academy
time 1
Award
name BAFTA
time 2
Award
name Gloden Globes
time 3
Java(你需要更改paths/filenames)
final String TXT_PATH = "file:///C:/tmp/input.txt";
final String XSLT_PATH = "C:/tmp/txt2xml.xsl";
final String XML_PATH = "C:/tmp/test_xml_result.xml";
TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl();
Transformer transformer = tFactory.newTransformer(new StreamSource(new File(XSLT_PATH)));
transformer.setParameter("input-uri", TXT_PATH);
transformer.transform(new StreamSource(new File(XSLT_PATH)),new StreamResult(new File(XML_PATH)));
XSLT 2.0
同上
输出
<Jamesfilms>
<Heros>
<Firstname>Sean</Firstname>
<Lastname>Connery</Lastname>
<DOB>25-08-1930</DOB>
</Heros>
<Films>
<Dr.No>1962</Dr.No>
<Goldfinger>1964</Goldfinger>
<Thunerball>1965</Thunerball>
</Films>
<Award>
<name>Academy</name>
<time>1</time>
</Award>
<Award>
<name>BAFTA</name>
<time>2</time>
</Award>
<Award>
<name>Gloden Globes</name>
<time>3</time>
</Award>
</Jamesfilms>
但是,由于您使用的是 Saxon,因此可以使用 s9api 并指定一个初始模板。这是我将采用的方式,而不是将样式表作为输入传递给转换。
示例...
Java
final String TXT_PATH = "file:///C:/tmp/input.txt";
final String XSLT_PATH = "C:/tmp/txt2xml.xsl";
final String XML_PATH = "C:/tmp/test_xml_result.xml";
Processor processor = new Processor(false);
Serializer serializer = processor.newSerializer();
serializer.setOutputFile(new File(XML_PATH));
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable executable = compiler.compile(new StreamSource(new File(XSLT_PATH)));
XsltTransformer transformer = executable.load();
transformer.setInitialTemplate(new QName("root"));
transformer.setParameter(new QName("input-uri"), new XdmAtomicValue(TXT_PATH));
transformer.setDestination(serializer);
transformer.transform();
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/>
<xsl:param name="input-uri" as="xs:string"/>
<xsl:variable name="initData" as="node()">
<Jamesfilms>
<xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')">
<xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/>
<xsl:choose>
<xsl:when test="$tokens[1] castable as xs:QName">
<xsl:element name="{replace($tokens[1],'\s','')}">
<xsl:for-each select="$tokens[position() > 1]">
<xsl:variable name="tokens2" select="tokenize(.,'\s')"/>
<xsl:choose>
<xsl:when test="$tokens2[1] castable as xs:QName">
<xsl:element name="{$tokens2[1]}">
<xsl:value-of select="$tokens2[position()>1]" separator=" "/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Jamesfilms>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/" name="root">
<xsl:apply-templates select="$initData"/>
</xsl:template>
<!--Add additional templates to do further transforming of the initial data ($initData).-->
</xsl:stylesheet>
输入和输出是一样的。如果您需要我将 java 导入添加到示例中,请告诉我。