diff --git a/Makefile b/Makefile index a6e91811..961f1d6f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SHELL ?= /bin/bash endif #JAR_VERSION := $(shell mvn -q -Dexec.executable="echo" -Dexec.args='$${project.version}' --non-recursive exec:exec -DforceStdout) -JAR_VERSION := 1.55 +JAR_VERSION := 1.56 JAR_FILE := mn2pdf-$(JAR_VERSION).jar all: target/$(JAR_FILE) diff --git a/README.adoc b/README.adoc index 2dea0cc7..55fb3234 100644 --- a/README.adoc +++ b/README.adoc @@ -17,14 +17,14 @@ You will need the Java Development Kit (JDK) version 8, Update 241 (8u241) or hi [source,sh] ---- -java -Xss5m -Xmx2048m -jar target/mn2pdf-1.55.jar --xml-file --xsl-file --pdf-file [--syntax-highlight] +java -Xss5m -Xmx2048m -jar target/mn2pdf-1.56.jar --xml-file --xsl-file --pdf-file [--syntax-highlight] ---- e.g. [source,sh] ---- -java -Xss5m -Xmx2048m -jar target/mn2pdf-1.55.jar --xml-file tests/G.191.xml --xsl-file tests/itu.recommendation.xsl --pdf-file tests/G.191.pdf +java -Xss5m -Xmx2048m -jar target/mn2pdf-1.56.jar --xml-file tests/G.191.xml --xsl-file tests/itu.recommendation.xsl --pdf-file tests/G.191.pdf ---- === PDF encryption features @@ -100,7 +100,7 @@ Update version in `pom.xml`, e.g.: ---- org.metanorma.fop mn2pdf -1.55 +1.56 Metanorma XML to PDF converter ---- @@ -111,8 +111,8 @@ Tag the same version in Git: [source,xml] ---- -git tag v1.55 -git push origin v1.55 +git tag v1.56 +git push origin v1.56 ---- Then the corresponding GitHub release will be automatically created at: diff --git a/pom.xml b/pom.xml index 4d3e2463..9dfb0019 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.metanorma.fop mn2pdf - 1.55 + 1.56 Metanorma XML to PDF converter jar https://www.metanorma.org @@ -237,6 +237,10 @@ js-scriptengine 21.1.0 - + + net.sourceforge.cssparser + cssparser + 0.9.29 + diff --git a/src/main/java/org/metanorma/fop/Util.java b/src/main/java/org/metanorma/fop/Util.java index 205a79bc..620b7b3f 100644 --- a/src/main/java/org/metanorma/fop/Util.java +++ b/src/main/java/org/metanorma/fop/Util.java @@ -61,6 +61,7 @@ import javax.imageio.stream.ImageInputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.TransformerFactory; import javax.xml.xpath.XPath; @@ -70,14 +71,21 @@ import javax.xml.xpath.XPathFactory; import static org.metanorma.Constants.DEBUG; import static org.metanorma.fop.SourceXMLDocument.tmpfilepath; + +import com.steadystate.css.dom.CSSStyleRuleImpl; +import com.steadystate.css.parser.CSSOMParser; +import com.steadystate.css.parser.SACParserCSS3; import org.metanorma.fop.fonts.FOPFont; import org.metanorma.utils.LoggerHelper; +import org.w3c.css.sac.SelectorList; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.w3c.dom.css.*; import org.xml.sax.InputSource; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; +import org.xml.sax.SAXException; /** * @@ -708,4 +716,71 @@ public static String encodeBase64(String input) { } return Base64.getEncoder().encodeToString(input.getBytes()); } + + public static Node parseCSS(String cssString) { + StringBuilder sbCSSxml = new StringBuilder(); + try { + sbCSSxml.append(""); + org.w3c.css.sac.InputSource source = new org.w3c.css.sac.InputSource(new StringReader(cssString)); + CSSOMParser parser = new CSSOMParser(new SACParserCSS3()); + CSSStyleSheet sheet = parser.parseStyleSheet(source, null, null); + + CSSRuleList rules = sheet.getCssRules(); + for (int i = 0; i < rules.getLength(); i++) { + final CSSRule rule = rules.item(i); + + if (rule instanceof CSSStyleRule) { + CSSStyleRule styleRule = (CSSStyleRule) rule; + SelectorList selectorList = ((CSSStyleRuleImpl) rule).getSelectors(); + + //System.out.println("selector: " + styleRule.getSelectorText()); + CSSStyleDeclaration styleDeclaration = styleRule.getStyle(); + StringBuilder properties = new StringBuilder(); + for (int j = 0; j < styleDeclaration.getLength(); j++) { + String property = styleDeclaration.item(j); + String value = styleDeclaration.getPropertyCSSValue(property).getCssText(); + //System.out.println("property: " + property); + //System.out.println("value: " + value); + properties.append(""); + } + + for (int s = 0; s < selectorList.getLength(); s++) { + String selectorText = selectorList.item(s).toString(); + if (selectorText.contains(".")) { + selectorText = selectorText.substring(selectorText.lastIndexOf(".") + 1).trim(); + } else if (selectorText.contains(" ")) { + selectorText = selectorText.substring(selectorText.lastIndexOf(" ") + 1).trim(); + } + //selectorText = selectorText.replaceAll("sourcecode \\.",""); + //System.out.println("selector: " + selectorText); + sbCSSxml.append(""); + sbCSSxml.append(properties); + sbCSSxml.append(""); + } + } + } + sbCSSxml.append(""); + + } catch (IOException e) { + logger.severe("CSS parsing error: " + e.toString()); + sbCSSxml.setLength(0); + sbCSSxml.append(""); + } + Node node = null; + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document parsed = builder.parse(new InputSource(new StringReader(sbCSSxml.toString()))); + node = parsed.getDocumentElement(); + } catch (IOException | ParserConfigurationException | SAXException e) { + logger.severe("CSS parsing error: " + e.toString()); + } + return node; + } } diff --git a/src/main/resources/tables_only.xsl b/src/main/resources/tables_only.xsl index 652e603b..f56f5b94 100644 --- a/src/main/resources/tables_only.xsl +++ b/src/main/resources/tables_only.xsl @@ -98,6 +98,7 @@ + diff --git a/src/test/java/org/metanorma/fop/mn2pdfTests.java b/src/test/java/org/metanorma/fop/mn2pdfTests.java index 2b2e0b5a..5754529d 100644 --- a/src/test/java/org/metanorma/fop/mn2pdfTests.java +++ b/src/test/java/org/metanorma/fop/mn2pdfTests.java @@ -1,10 +1,6 @@ package org.metanorma.fop; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.StringWriter; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -12,12 +8,14 @@ import java.util.logging.Handler; import java.util.logging.Logger; import java.util.logging.StreamHandler; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; +import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import com.steadystate.css.dom.CSSStyleRuleImpl; +import com.steadystate.css.parser.CSSOMParser; +import com.steadystate.css.parser.SACParserCSS3; import org.apache.commons.cli.ParseException; import org.apache.pdfbox.cos.COSName; @@ -33,6 +31,8 @@ import org.apache.pdfbox.text.PDFTextStripper; import org.junit.Rule; import org.junit.Test; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.BeforeClass; @@ -45,7 +45,11 @@ import static org.metanorma.Constants.ERROR_EXIT_CODE; import static org.metanorma.fop.PDFGenerator.logger; import org.metanorma.utils.LoggerHelper; +import org.w3c.css.sac.InputSource; +import org.w3c.css.sac.Selector; +import org.w3c.css.sac.SelectorList; import org.w3c.dom.Node; +import org.w3c.dom.css.*; public class mn2pdfTests { @@ -399,6 +403,27 @@ public void checkSpacesInPDF() throws ParseException { assertTrue(pdftext.contains("the_integers") && pdftext.contains("elementary_space") && pdftext.contains("make_elementary_space")); } + @Test + public void checkCSSparsing() throws IOException { + String cssString = "sourcecode .c, sourcecode .ch {\n" + + " color: #FF0000;\n" + + "}"; + Node xmlNode = Util.parseCSS(cssString); + String xmlStr = nodeToString(xmlNode); + assertEquals("", xmlStr); + } + + private static String nodeToString(Node node) { + StringWriter sw = new StringWriter(); + try { + Transformer t = TransformerFactory.newInstance().newTransformer(); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + t.transform(new DOMSource(node), new StreamResult(sw)); + } catch (TransformerException te) { + System.out.println("nodeToString Transformer Exception"); + } + return sw.toString(); + } @Test