Java 无法使用xslt从xml到csv获取所需数据
我正在尝试将数据从XML加载到csv,但缺少一些节点数据。 下面是我的Java代码Java 无法使用xslt从xml到csv获取所需数据,java,xml,csv,xslt,Java,Xml,Csv,Xslt,我正在尝试将数据从XML加载到csv,但缺少一些节点数据。 下面是我的Java代码 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.text.ParseException; import javax.xml.namespace.QNam
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class XML2CSV {
public static int transform(InputStream is, OutputStream os, Transformer transformer, QName name) throws XMLStreamException, TransformerException {
long time1 = System.nanoTime();
// Open input & output files
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
factory.setProperty(XMLInputFactory.IS_VALIDATING, false);
XMLStreamReader reader = factory.createXMLStreamReader(is);
// In case you want to check which implementation is used.
// Woodstox is a bit faster, but not worth adding extra dependency.
Result result = new StreamResult(os);
transformer.transform(new StAXSource(reader), result);
int count = 0;
while (reader.hasNext()) {
if (reader.getEventType() == XMLStreamReader.START_ELEMENT && name.equals(reader.getName())) {
// System.out.println("FOUND " + count);
count++;
if (count % 1000 == 0) {
long time2 = System.nanoTime();
double ms = (time2 - time1) / 1000000.0;
System.out.format("Time=%.2fms Rows=%d%n", ms, count);
}
} else if (reader.getEventType() == XMLStreamReader.START_ELEMENT) {
// System.out.println("Start "+reader.getName()+" != "+name);
}
reader.next();
}
long time2 = System.nanoTime();
double ms = (time2 - time1) / 1000000.0;
System.out.format("Total Time=%.2fms Total rows=%d%n", ms, count);
return count;
}
public static void main(String arg[]) throws Exception {
// Parse command line options
File xsltFile;
File inputFile;
File outputFile;
String tagName;
String namespace;
try {
String xsltFileName = parse("-x", arg, "XSLT sheet", true);
String inputFileName = parse("-f", arg, "Input file", true);
String outputFileName = parse("-o", arg, "Output file", true);
tagName = parse("-t", arg, "Tag name", true);
namespace = parse("-n", arg, "Tag Namespace URL", false);
xsltFile = new File(xsltFileName);
inputFile = new File(inputFileName);
outputFile = new File(outputFileName);
} catch (ParseException e) {
System.err.println(e.getMessage());
System.err.println("Syntax: XML2CSV -f <input file> -o <output file> -x <XSLT stylesheet> -t <Tag name> [-n <namespace URL>]");
System.err.println("Will split given file on given tag with given namespace.");
System.err.println("Will process contents of each tag using given XSLT.");
System.exit(1);
return;
}
if (!xsltFile.exists()) {
System.err.println("File not found " + xsltFile.getAbsolutePath());
System.exit(1);
}
if (!inputFile.exists()) {
System.err.println("File not found " + inputFile.getAbsolutePath());
System.exit(1);
}
// Open XSLT stylesheet
StreamSource stylesource = new StreamSource(xsltFile);
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
// Create XML tag name which is used to break up XML into rows
final QName name;
if (namespace != null) {
name = new QName(namespace, tagName);
} else {
name = new QName(tagName);
}
System.out.println("Will look for tag " + name + " in namespace " + namespace);
FileOutputStream fos = null;
FileInputStream fis = null;
try {
// Open input & output files
fis = new FileInputStream(inputFile);
fos = new FileOutputStream(outputFile);
transform(fis, fos, transformer, name);
} finally {
if (fos != null) {
fos.close();
}
if (fis != null) {
fis.close();
}
}
}
// Teo - inefficient, but who cares
private static String parse(String option, String[] arg, String desc, boolean required) throws ParseException {
for (int i = 0; i < arg.length; i++) {
if (option.equals(arg[i])) {
if (i + 1 < arg.length) {
String value = arg[i + 1].trim();
return value;
} else {
throw new ParseException(option + " must be followed by an argument", i);
}
}
}
if (required) {
throw new ParseException(desc + " is required", 0);
} else {
return null;
}
}
}
请帮助我理解我在XSL代码中的错误所在,以及如何获取列数据
谢谢大家! 尝试使用设置蓄能器
<xsl:accumulator name="MktSegID" streamable="yes" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="x:Batch/x:MktDef" select="string(@MktSegID)"/>
</xsl:accumulator>
使用
正如在一篇评论中所说的,它代替了
而出现了您想要的
好吧,在您的XML代码片段中,Evnt
元素有一个属性为Exch=“XLDX”
的父元素,因此它不是。/../Exch
我想您想要。/@Exch
。嗨,Martin,谢谢您的更新。那MktSegId呢?如何获取该属性?这是前面MktDef
元素的MktSegID
属性吗?好的,使用普通的XSLT/XPath,您可以导航到前面的sibling::MktDef[1]/@MktSegID元素,但我注意到您使用的是
和XSLT 3.0,因此可能无法导航。嗨,Martin,您能给我一些关于“前面的sibling::MktDef[1]/@MktSegID”的示例吗没有内存消耗,因为我有超过1 GB的xml文件数据要解析。您首先需要编辑您的问题以解释和显示输入xml的结构,目前尚不清楚xml的大小是由什么组成的,是否有一个批处理
和一个MktDef
以及数千个SecDef
和Evnt
子元素,或者是否有数千个批处理
元素。因此,在不知道确切的重复结构的情况下,无法判断是否以及如何解决该任务。嗨,Martin,我已经更新了您上面提到的xsl s,但我遇到了以下错误,在google中尝试过,但无法了解错误是什么,致命错误:“错误检查表达式类型”funcall(之前的累加器,[literal expr(MktSegID)])'。:错误检查表达式“funcall(acculator before,[literal expr(MktSegID)])”的类型。线程“main”javax.xml.transform.TransformerConfigurationException中的异常:错误检查表达式“funcall”(acculator before,[literal expr(MktSegID)])的类型’。这是XSLT 3.0代码,使用流式处理,因此您需要使用Saxon 9.8 EE和com.saxonica.config.StreamingTransformerFactory
即Transformer Transformer=new com.saxonica.config.StreamingTransformerFactory().newTransformer(stylesource)
和提供SaxSource或StreamSource作为输入。否则,流式XSLT 3.0的全部使用是不可能的。嗨,马丁,谢谢你的快速响应。我试图将Saxon 9.8 EE添加到我的客户项目中,并了解到它不是一个自由软件,客户对此不满意,因为我们在这类项目上不会做太多工作XML文件。您能告诉我是否有免费软件可以获得此功能吗?提前谢谢!我不知道有任何开源XSLT 3.0实现支持流式传输。当然,SAX和XMLStreamReader是Java JRE的一部分,因此您需要使用这些API和使用它们编写的Java程序来创建CSV您好,Martin,非常感谢您的快速响应和宝贵的解决方案。
<?xml version="1.0" encoding="ISO-8859-1"?>
<FIXML xsi:schemaLocation="http://www.fixprotocol.org/FIXML-5-0-SP2 fixml-main-5-0-SP2_.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2" s="2012-04-23" v="FIX.5.0SP2">
<Batch ID="RPTTA111PUBLI20170509">
************ This is one set of loop************
<MktDef MktID="XEUR" MktSegID="19699" EfctvBizDt="2017-05-11" NxtEfctvBizDt="2017-05-15" MktSeg="FCEA" MarketSegmentDesc="FUT ON EUR AUD" Sym="DE000A160WW0" ParentMktSegmID="FCUR" Ccy="AUD" MktSegStat="10" USFirmFlag="Y" PartID="1">
<Undly Exch="XREU" Sym="CEA" ID="EU0009654748" Src="4" PrevClsPx="1.47"/>
</MktDef>
<SecDef PriSetPx="68708.52">
<Instrmt ID="221096" Src="M" SecTyp="FUT" Status="1" Exch="XLDX" ProdCmplx="1" CFI="FFMCSX" MatDt="2024-12-17" MMY="202412" Mult="1" ValMeth="FUT" SettlMeth="C" PxPrcsn="2" MinPxIncr="0.01" MinPxIncrAmt="0.01">
<Evnt EventTyp="7" Dt="2024-12-17"/>
</Instrmt>
</SecDef>
<SecDef>
.
.
.
</SecDef>
<SecDef>
.
.
.
</SecDef>
<SecDef>
.
.
.
</SecDef>
************ This is one set of loop************
############ This will continue n number of times having millions of line###########
</Batch>
</FIXML>
PriSetPx TxnTm ID Src EventTyp Dt Exch MktSegID
<xsl:accumulator name="MktSegID" streamable="yes" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="x:Batch/x:MktDef" select="string(@MktSegID)"/>
</xsl:accumulator>
<xsl:value-of select="concat($quote, normalize-space(../../../@MktSegID), $quote)" />
<xsl:value-of select="concat($quote, accumulator-before('MktSegID'), $quote)" />