LadyPreis Geschrieben 8. Februar 2010 Geschrieben 8. Februar 2010 Hallo zusammen, mal wieder ein Problem. Ich will mittels Apache FOP eine XML-Datei (inkl. XSLT-Stylesheet) mittels Java-Code in ein PDF umwandeln. Die Beispiele auf der Apache-Seite hab ich durchgearbeitet und weitestgehend auch verstanden. Allerdings klappt die Umsetzung in meinem Programm nicht so, wie sie soll. Erstmal mein Code: File xmlfile = new File("D:/src.xml"); File xsltfile = new File("D:/stylesheet.xsl"); File fofile = new File("D:/fo_objekt.fo"); File pdffile = new File("D:/output.pdf"); //XML2FO OutputStream out = new FileOutputStream(fofile); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(new StreamSource(xsltfile)); Source src = new StreamSource(xmlfile); Result res = new StreamResult(out); transformer.transform(src, res); //FO2PDF FopFactory fopfactory = FopFactory.newInstance(); FOUserAgent foUserAgent = fopfactory.newFOUserAgent(); out = new BufferedOutputStream(new FileOutputStream(pdffile)); Fop fop = fopfactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); factory = TransformerFactory.newInstance(); transformer = factory.newTransformer(); src = new StreamSource(fofile); res = new SAXResult(fop.getDefaultHandler()); transformer.transform(src, res); Soweit so gut. Wenn ich diese Implementierung ausführe, bekomme ich folgende Exception: javax.xml.transform.TransformerException: org.apache.fop.fo.ValidationException: Error: First element must be the fo:root formatting object. Found (Namespace URI: "", Local Name: "HTML") instead. Please make sure you're producing a valid XSL-FO document. at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:501) at de.gzs.fop.start.main(start.java:138) Caused by: org.apache.fop.fo.ValidationException: Error: First element must be the fo:root formatting object. Found (Namespace URI: "", Local Name: "HTML") instead. Please make sure you're producing a valid XSL-FO document. at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.startElement(FOTreeBuilder.java:262) at org.apache.fop.fo.FOTreeBuilder.startElement(FOTreeBuilder.java:163) at org.apache.xalan.transformer.TransformerIdentityImpl.startElement(TransformerIdentityImpl.java:1072) at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source) at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source) at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484) ... 1 more --------- org.apache.fop.fo.ValidationException: Error: First element must be the fo:root formatting object. Found (Namespace URI: "", Local Name: "HTML") instead. Please make sure you're producing a valid XSL-FO document. at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.startElement(FOTreeBuilder.java:262) at org.apache.fop.fo.FOTreeBuilder.startElement(FOTreeBuilder.java:163) at org.apache.xalan.transformer.TransformerIdentityImpl.startElement(TransformerIdentityImpl.java:1072) at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source) at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source) at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484) at de.gzs.fop.start.main(start.java:138) Wenn ich mir die erstellte FO-Datei ansehe, erkenne ich auch das Problem: Der Output ist kein FO-Objekt, sondern reines HTML. Weiß jemand, was ich falsch mache? JDK 1.6 FOP 0.95 Gruß Die Lady Zitieren
kingofbrain Geschrieben 8. Februar 2010 Geschrieben 8. Februar 2010 Weiß jemand, was ich falsch mache? Ja, Du zeigst nicht die relevanten Teile Deiner Quellen. Wir wissen nicht, was im XSL und im Ausgangs-XML drinsteht. Und wir wissen auch nicht, was im .fo drinsteht, aber es scheint HTML zu sein. Kann es sein, dass das Stylesheet mit dem XML (HTML?) nichts macht und es einfach durchreicht? Dann hättest Du als .fo das Ausgangs-HTML und das führt dann zum Fehler. Peter Zitieren
LadyPreis Geschrieben 8. Februar 2010 Autor Geschrieben 8. Februar 2010 I'm sorry hier die Daten: XML-Datei: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE IC SYSTEM "pro.dtd"> <?xml-stylesheet type="text/xsl" href="pro.xsl"?> <IC xmlns:PF="http://www.url.tld/xml"> <IC_HEADER> <ICHDR>Kundendaten</ICHDR> <ICPFORM>H</ICPFORM> <ICVVNR>01.01</ICVVNR> <ICVVTXT>http://www.url.tld</ICVVTXT> </IC_HEADER> <AVIS> <BGM><PF:D_0037>0</PF:D_0037></BGM> <DTM> <C507> <D_2005 Value="000"></D_2005> <D_2380 Desc="Datum">01011970</D_2380> </C507> </DTM> <DTM> <C507> <D_2005 Value="001"></D_2005> <D_2380 Desc="Datum2">01011970</D_2380> </C507> </DTM> ... und so weiter Stylesheet: <?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:PF="http://www.url.tld/xml"> <xsl:output method="html" indent="no"/> <xsl:template match="/IC"> <xsl:for-each select="AVIS"> <HTML> <BODY bgcolor="#FFFFFF"> <DIV align="left"> <TABLE width="100%" border="0" cellspacing="0" cellpadding="0"> <TR> <TD> <xsl:call-template name="Header"/> </TD> </TR> <TR> <TD height="50"> <xsl:text disable-output-escaping="yes"> </xsl:text> </TD> </TR> <TR> <TD> <xsl:call-template name="Body"/> </TD> </TR> ... und so weiter Und der output in der FO-Datei: <HTML xmlns:PF="http://www.post.ch/xml"><BODY bgcolor="#FFFFFF"><DIV align="left"><TABLE cellpadding="0" cellspacing="0" border="0" width="100%"><TR><TD><TABLE cellpadding="5" cellspacing="0" border="0" height="100%" width="100%"><TR><TD height="0" width="60%"></TD><TD height="0" width="40%"></TD></TR><TR><TD> </TD><TD height="68" align="left" nowrap><IMG src="grafik.gif" alt="" width="200"></TD></TR><TR valign="top"><TD nowrap><FONT size="1">hier gehen die Dokumentendaten los</FONT> ... Zitieren
kingofbrain Geschrieben 8. Februar 2010 Geschrieben 8. Februar 2010 Also meine Transformer-Zeiten sind zwar schon ein paar Tage her, aber ich würde sagen "works as designed". Du sagst im Stylesheet, "jedes Element "AVIS" wird zu einem "HTML ..."", und zusätzlich gibst Du noch den Hinweis "<xsl:output method="html" indent="no"/>" (bei dem ich jetzt aus dem Kopf nicht weiß, was er *genau* macht, aber ich vermute, er wird HTML ausgeben und nicht einrücken ). Die .fo-Datei wird aber einen festgelegten Aufbau haben müssen, oder? Du wirst also ein Stylesheet schreiben müssen, das diesen Aufbau erzeugt. Sorry, das ich nicht konkreter werden kann, aber ich habe mit FO nur einmal zu tun gehabt, und das ist schon fast fünf Jahre her. Schöne Grüße, Peter Zitieren
LadyPreis Geschrieben 8. Februar 2010 Autor Geschrieben 8. Februar 2010 . Die .fo-Datei wird aber einen festgelegten Aufbau haben müssen, oder? die FO-Datei ist mir relativ unwichtig, da sie nur ein Zwischenprodukt zur Erzeugung der PDF ist. Das problem ist, dass das Stylesheet sich bei jedem Durchgang ändern kann, weswegen ich kein universelles erstellen kann. Muss ich mir wohl was Neues einfallen lassen, um die Umwandlung nach PDF zu machen. Jemand ne Idee? Zitieren
kingofbrain Geschrieben 8. Februar 2010 Geschrieben 8. Februar 2010 Auch wenn sie für Dich nur ein Zwischenschritt ist, so ist sie für die Transformation von .fo nach .pdf essentiell. Und damit ist auch der Aufbau wichtig. Du wirst ja immer irgendwie angeben müssen, wie die strukturierten Inhalten (XML) in das Layout des PDF gebracht werden sollen. Und da braucht es einen definierten einheitlichen Aufbau, z.B. .fo. Schöne Grüße, Peter Zitieren
LadyPreis Geschrieben 8. Februar 2010 Autor Geschrieben 8. Februar 2010 Das ist ja klar. Sorry, wenn das in meinem Post falsch rübergekommen ist. Mein Rpoblem ist wie schon beschrieben jedoch, dass sich der Aufbau des Stylesheets, und dadurch auch der gewünschte Aufbau der FO-Datei ändern kann. Da das projekt aktuell nicht zeitkritisch ist, habe ich mich auch noch nicht allzu sehr damit befasst, aber laut meinem Verständniss stoße ich doch dann an die Grenzen von FOP - oder sehe ich das falsch? Zitieren
kingofbrain Geschrieben 9. Februar 2010 Geschrieben 9. Februar 2010 Guten Morgen. Wenn es sich immer um eine FO-Datei handelt, dann ist das egal. Aber es kommt scheinbar keine FO-Datei bei Deinem Stylesheet raus, sondern eine XML-Datei (mit HTML Inhalt). Ich versuch es mal mit einem Beispiel aus der realen Welt: Wenn Du einen Diesel PKW fährst, dann kannst Du an verschiedenen Tankstellen Dieselkraftstoff tanken. Der PKW ist der Transformator (Kraftstoff in Bewegung), Diesel ist das Stylesheet (hier klemmt die Analogie ). So lange Du jetzt immer ein Diesel-Stylesheet in den Transformator schiebst, ist alles super, ob das jetzt ein Es** Diesel ist oder ein Ag** Diesel oder ein J** Diesel ist egal. Wenn Du aber mit Super ankommst, dann sagt der Transformator, das er mit der Eingabe nicht arbeiten kann. Wenn also alle Deine Stylesheets zwar unterschiedlich sind, aber immer Diesel (ähh, FO) ausspucken, dann passt alles. Schöne Grüße, Peter Zitieren
LadyPreis Geschrieben 9. Februar 2010 Autor Geschrieben 9. Februar 2010 Ich bekomme immer neue Stylesheets, welche immer HTML ausspucken. Generell ist es ja klar, dass ich den Output einfach auf FO umstellen muss. Da diese Stylesheets sich aber anscheinend sehr häufig ändern, kann ich doch nicht einfach mir ein fertiges Stylesheet für FO erstellen, da es ja nicht mehr den korrekt formatierten output ausspuckt. oder stehe ich grad auf dem Schlauch? Weißt du eigentlich auswendig, wie ich den Output von HTML auf FO umstelle? Sonst muss ich mal Tante Google fragen =) Zitieren
kingofbrain Geschrieben 9. Februar 2010 Geschrieben 9. Februar 2010 Ich kann Dir leider nicht sagen, wie man das umstellt. Ich gehe aber auch davon aus, dass man das nicht einfach mit einem Schalter umstellt, sondern dass sich die Dateien im Inhalt unterscheiden. Schau Dir am besten mal ein paar Beispiele zu FO-Dateien an, dann wird es bestimmt klarer. Schöne Grüße, Peter Zitieren
MartinUndDerWolf Geschrieben 19. Februar 2010 Geschrieben 19. Februar 2010 Hallo, ich weiß ja nicht, ob es schon zu spät ist, aber: Willst du einfach nur aus einer xml Datei eine pdf Datei erstellen? Dann brauchst du theoretisch diese fo Datei gar nicht. Wo hast du die überhaupt her? Ich habe damals einfach eine xsl Datei gebastelt, die von meinem Java Programm gelesen wird und mittels dynamisch erzeugter xml eine pdf erstellt hat. Das einzige Problem dabei ist, du musst eine xsl Datei erstellen. Sofern die pdf immer gleich aussieht und sich nur die Daten ändern, sollte das kein Problem sein. Falls du Interesse hast, kann ich das ganze gern einmal raus suchen und posten. bye, Martin Zitieren
LadyPreis Geschrieben 19. Februar 2010 Autor Geschrieben 19. Februar 2010 zu spät biste nicht - ich arbeite aktuell nicht an dem Projekt. Ich weiß nur, dass es auf mich zukommt, deswegen bin ich es in ner freien Minute nur schonmal im Kopf durchgegangen. So wie ich es aktuell aber sehe, besteht das Problem genau darin, dass sich diese xsl auch mal ändern kann - auch wenn sie aktuell immer identisch ist. Als aktuelle Problemlösung wäre es also möglich, sich eine solche xsl zu erstellen. Allerdings will ich eine möglichst flexible Lösung, bei der es nahezu keine Nacharbeiten erfordert, wie es bei einem fixen Stylesheet der Fall wäre. Aber da werde ich mir zu gegebener zeit einmal Gedanken machen. Dein Angebot, dass du mir das Ganze raussuchst, nehme ich aber gerne an =) Zitieren
MartinUndDerWolf Geschrieben 10. März 2010 Geschrieben 10. März 2010 Hallo, hier endlich einmal das Rausgesuchte: Im Prinzip wird aus einer xml und einer xsl eine sehr triviale Rechnung erstellt. Das Ganze ist in sofern dynamisch, als das die Rechnungsdaten durch die xml variieren können. Die xml Datei muß nicht extra gespeichert werden, es reicht, wenn sie als org.w3c.dom.Document vorliegt. <?xml version="1.0" encoding="UTF-8"?> <billing> <date>10.03.2010</date> <header>Rechnung</header> <bill-element> <name>Auftrag vom</name> <element>08.03.2010</element> </bill-element> <bill-element> <name>Anzahl</name> <element>96</element> </bill-element> <bill-element> <name>Kostenstelle</name> <element>1500000 </element> </bill-element> <bill-element> <name>Betrag</name> <element>904.74</element> <type>costs</type> </bill-element> </billing> Mit dieser xml Datei kann dann die Rechnung erstellt werden. Dazu nimmt man sich eine xsl Datei, die man vorher schon einmal erstellt hat. Man kann theoretisch auch einfach die xsl Datei im Quelltext erstellen und zwar wie die xml Datei als org.w3c.dom.Document. <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo"> <xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/> <xsl:param name="versionParam" select="'1.0'"/> <xsl:template match="billing"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm"> <fo:region-body margin="2cm 2cm 2cm 2cm"/> <fo:region-before region-name="xsl-region-before" extent="1cm"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="simpleA4"> <!-- A header with page numbering, must be defined in simple-page-master as region-before --> <fo:static-content flow-name="xsl-region-before" text-align="end" font-size="10pt" font-family="serif" line-height="14pt" color="black"> <fo:block>Seite <fo:page-number/> </fo:block> <fo:block> <xsl:value-of select="date"/> </fo:block> </fo:static-content> <fo:flow flow-name="xsl-region-body"> <!-- Header --> <fo:block font-size="16pt" font-weight="bold" space-before.optimum="2cm" space-after="2cm"> <fo:inline text-decoration="underline"><xsl:value-of select="header"/></fo:inline> </fo:block> <!-- content --> <fo:block font-size="10pt"> <fo:table table-layout="fixed" width="100%" border-collapse="separate"> <fo:table-column column-width="2cm"/> <fo:table-column column-width="0.5cm"/> <fo:table-column column-width="2cm"/> <fo:table-body> <xsl:apply-templates select="bill-element"/> </fo:table-body> </fo:table> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <!-- ========================= --> <!-- child element: bill --> <!-- ========================= --> <xsl:template match="bill-element"> <fo:table-row> <fo:table-cell> <fo:block> <xsl:value-of select="name"/> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> : </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:if test="type = 'costs'"> <xsl:attribute name="font-weight">bold</xsl:attribute> </xsl:if> <xsl:value-of select="element"/> </fo:block> </fo:table-cell> </fo:table-row> </xsl:template> </xsl:stylesheet> Nun kann wie übrigens auch hier beschrieben: Apache FOP: Embedding die pdf Datei erstellt werden. File xslFile = new File("bill.xsl"); File pdfFile = new File("bill.pdf"); BufferedOutputStream buffOut = new BufferedOutputStream(new FileOutputStream(pdfFile)); FopFactory fopFactory = FopFactory.newInstance(); FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); // construct fop with pdf as output format Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, buffOut); // setup xslt TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer transformer = transFactory.newTransformer(new StreamSource(xslFile)); // input for xslt Source src = new DOMSource(billDoc); // resulting SAX events must be piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); // start xslt transformation and FOP processing transformer.transform(src, res); buffOut.close(); Die Kommentare erklären alles, denke ich. Prinzip ist einfach, dass du eine Source für die xml Datei übergibst und die xsl Datei in Form eines SAXResult. Es gibt auch noch die Möglichkeit die xsl ebenfalls als Source zu übergeben, wird ebenfalls in dem Link weiter oben erklärt. Fragen, Meinungen, Probleme? Für die xsl Datei hier noch ein Link zu einem netten Tutorial XSL-FO. Falls das alles ein bißchen zu viel ist, hier noch die Alternative: Beitrag aus diesem Forum bye, Martin Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.