2017-08-23 8 views
0

XMLからcsvにデータをロードしようとしていますが、欠落しているノードのデータがあります。以下 は、私のJavaコードであるxsltを使用してxmlからcsvに必要なデータを取得できません

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

これは、

<?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xmlns:x="http://www.fixprotocol.org/FIXML-5-0-SP2" 
          xsi:schemaLocation="http://www.fixprotocol.org/FIXML-5-0-SP2 fixml-main-5-0-SP2_.xsd" 
          xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
          exclude-result-prefixes="xs math"> 


<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:mode streamable="yes" use-accumulators="MktSegID"/> 
<xsl:output method="text" encoding="utf-8" /> 

<xsl:param name="delim" select="','" /> 
<xsl:param name="quote" select="'&quot;'" /> 
<xsl:param name="break" select="'&#xA;'" /> 


<xsl:template match="/"> 
<xsl:text>PriSetPx,TxnTm,ID,Src,EventTyp,Dt,Exch,MktSegID </xsl:text> 
<xsl:text>&#xA;</xsl:text> 
<xsl:apply-templates select="descendant::x:Evnt"/> 
</xsl:template> 

<xsl:template match="x:Evnt"> 
<xsl:value-of select="concat($quote, normalize-space(../../@PriSetPx), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="concat($quote, normalize-space(../../@TxnTm), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="concat($quote, normalize-space(../@ID), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="concat($quote, normalize-space(../@Src), $quote)" /><xsl:value-of select="$delim" /> 

<xsl:value-of select="concat($quote, normalize-space(@EventTyp), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="concat($quote, normalize-space(@Dt), $quote)" /><xsl:value-of select="$delim" /> 

<xsl:value-of select="concat($quote, normalize-space(../@Exch), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="concat($quote, accumulator-before('MktSegID'), $quote)" /><xsl:value-of select="$delim" /> 
<xsl:value-of select="$break" /> 
</xsl:template> 
</xsl:stylesheet> 

私のXSLファイルであり、ここで私のサンプルXMLで、

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

出力は列として、次のように来る必要があります@Exchと@MktSegIdのデータはありません。

PriSetPx TxnTm ID Src EventTyp Dt Exch MktSegID 

XSLコードのどこで間違ったのか、列データを取得する方法を理解してください。

ありがとうございました!

+0

あなたのXMLスニペットでは、 'Evnt'要素に' Exch = "XLDX" 'という親要素があるので、' ../../@ Exch'の代わりに '../@ Exch'。 –

+0

こんにちはマーティン、更新していただきありがとうございます。 MktSegIdはどうですか?それをどうやって手に入れますか? –

+0

これは先の 'MktDef'要素の' MktSegID'属性ですか?通常のXSLT/XPathでは 'preceding-sibling :: MktDef [1]/@ MktSegID'という要素に移動しますが、' 'とXSLT 3.0、そのため、ナビゲートすることができない可能性があります。 –

答えて

1

<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:mode<xsl:mode streamable="yes" use-accumulators="MktSegID"/>を追加して、既にコメントで述べたように代わりの

<xsl:value-of select="concat($quote, normalize-space(../../../@MktSegID), $quote)" /> 

使用

<xsl:value-of select="concat($quote, accumulator-before('MktSegID'), $quote)" /> 

、それが現れると、アキュムレータを設定してみてください<xsl:value-of select="concat($quote, normalize-space(../../@Exch), $quote)" />の代わりにあなたはむしろ<xsl:value-of select="concat($quote, normalize-space(../@Exch), $quote)" />

+0

こんにちはマーティン、私は上記のxslを更新しましたが、私はエラーが下になっている、グーグルで試してみましたが、エラーのアイデアを得ることができません 致命的なエラー: '式のタイプをチェック中のエラー' funcall -before、[literal-expr(MktSegID)]) '。' :式 'funcall(accumulator-before、[literal-expr(MktSegID)])'の型をチェックする際にエラーが発生しました。 スレッド "main"の例外javax.xml.transform.TransformerConfigurationException:式 'funcall(accumulator-before、[literal-expr(MktSegID)])の型のチェックでエラーが発生しました。 –

+0

それはストリーミングを利用する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の全体的な使用は不可能です。 –

+0

こんにちはMartin、あなたの迅速な対応に感謝します。私はクライアントプロジェクトにSaxon 9.8 EEを追加しようとしていましたが、フリーソフトウェアではないことを知りました。このタイプのXMLファイルではあまり働かないため、クライアントはこれに満足できません。この機能を利用するためのフリーソフトウェアがあれば教えてください。前もって感謝します! –

関連する問題