diff --git a/src/main/java/com/siemens/ct/exi/main/api/stream/StAXEncoder.java b/src/main/java/com/siemens/ct/exi/main/api/stream/StAXEncoder.java index 7db698dc..40ffc5e0 100644 --- a/src/main/java/com/siemens/ct/exi/main/api/stream/StAXEncoder.java +++ b/src/main/java/com/siemens/ct/exi/main/api/stream/StAXEncoder.java @@ -85,6 +85,9 @@ public class StAXEncoder implements XMLStreamWriter { protected final boolean preserveComment; protected final boolean preservePI; + // indicate whether an "empty" element was started + protected boolean emptyElement; + // AT or NS Events pending protected boolean pendingATs; @@ -115,6 +118,7 @@ public void setOutputStream(OutputStream os) throws EXIException, } protected void init() { + emptyElement = false; pendingATs = false; exiAttributes.clear(); nsContext.reset(); @@ -289,8 +293,12 @@ protected void checkPendingATEvents() throws EXIException, IOException { // encode NS decls and attributes encoder.encodeAttributeList(exiAttributes); exiAttributes.clear(); - pendingATs = false; + + if (emptyElement) { + encoder.encodeEndElement(); + emptyElement = false; + } } } @@ -618,7 +626,9 @@ public void writeEmptyElement(String namespaceURI, String localName) public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { this.writeStartElement(prefix, localName, namespaceURI); - this.writeEndElement(); + // Note: we cannot close the element immediately since attributes might follow + // this.writeEndElement(); + emptyElement = true; } public void writeStartDocument(String version) throws XMLStreamException { diff --git a/src/test/java/com/siemens/ct/exi/main/ParallelTest.java b/src/test/java/com/siemens/ct/exi/main/ParallelTest.java index b2cbaf8f..c420ef34 100644 --- a/src/test/java/com/siemens/ct/exi/main/ParallelTest.java +++ b/src/test/java/com/siemens/ct/exi/main/ParallelTest.java @@ -48,6 +48,7 @@ import com.siemens.ct.exi.main.data.AbstractTestCase; import com.siemens.ct.exi.main.data.TestXSDResolver; +@Ignore("https://github.com/EXIficient/exificient/issues/45") public class ParallelTest extends AbstractTestCase { static final int ENCODE_THREADS = 4; // 8 diff --git a/src/test/java/com/siemens/ct/exi/main/api/stream/StAXCoderTestCase.java b/src/test/java/com/siemens/ct/exi/main/api/stream/StAXCoderTestCase.java index 0a469561..fcda8bd7 100644 --- a/src/test/java/com/siemens/ct/exi/main/api/stream/StAXCoderTestCase.java +++ b/src/test/java/com/siemens/ct/exi/main/api/stream/StAXCoderTestCase.java @@ -527,6 +527,96 @@ public void testIssue18_simpifiedNoPrefix() throws AssertionFailedError, } } + + // https://github.com/EXIficient/exificient/issues/43 + public void testEmptyElement() throws Exception { + // + // + // myTitle + // + + EXIFactory ef = DefaultEXIFactory.newInstance(); + + // Version A: empty Element with SE ... EE + { + StAXEncoder staxEncoder = new StAXEncoder(ef); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + staxEncoder.setOutputStream(baos); + + staxEncoder.writeStartDocument(); + staxEncoder.writeStartElement("head"); + staxEncoder.writeStartElement("link"); + staxEncoder.writeAttribute("rel", "stylesheet"); + staxEncoder.writeAttribute("href", "css/xmlwriter01.css"); + staxEncoder.writeEndElement(); + staxEncoder.writeStartElement("title"); + staxEncoder.writeCharacters("myTitle"); + staxEncoder.writeEndElement(); + staxEncoder.writeEndElement(); + staxEncoder.writeEndDocument(); + + // decode + StAXDecoder staxDecoder = new StAXDecoder(ef); + staxDecoder.setInputStream(new ByteArrayInputStream(baos.toByteArray())); + _checkDecodeEmptyElement(staxDecoder); + } + + + // Version B: using writeEmptyElement + { + StAXEncoder staxEncoder = new StAXEncoder(ef); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + staxEncoder.setOutputStream(baos); + + staxEncoder.writeStartDocument(); + staxEncoder.writeStartElement("head"); + staxEncoder.writeEmptyElement("link"); + staxEncoder.writeAttribute("rel", "stylesheet"); + staxEncoder.writeAttribute("href", "css/xmlwriter01.css"); + staxEncoder.writeStartElement("title"); + staxEncoder.writeCharacters("myTitle"); + staxEncoder.writeEndElement(); + staxEncoder.writeEndElement(); + staxEncoder.writeEndDocument(); + + // decode + StAXDecoder staxDecoder = new StAXDecoder(ef); + staxDecoder.setInputStream(new ByteArrayInputStream(baos.toByteArray())); + _checkDecodeEmptyElement(staxDecoder); + } + } + + void _checkDecodeEmptyElement(StAXDecoder staxDecoder) throws Exception { + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.START_ELEMENT, staxDecoder.next()); + assertEquals("head", staxDecoder.getName().getLocalPart()); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.START_ELEMENT, staxDecoder.next()); + assertEquals("link", staxDecoder.getName().getLocalPart()); + + assertEquals(2, staxDecoder.getAttributeCount()); + assertEquals("rel", staxDecoder.getAttributeName(0).getLocalPart()); + assertEquals("stylesheet", staxDecoder.getAttributeValue(0)); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.END_ELEMENT, staxDecoder.next()); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.START_ELEMENT, staxDecoder.next()); + assertEquals("title", staxDecoder.getName().getLocalPart()); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.CHARACTERS, staxDecoder.next()); + assertEquals("myTitle", new String(staxDecoder.getTextCharacters())); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.END_ELEMENT, staxDecoder.next()); + + assertTrue(staxDecoder.hasNext()); + assertEquals(XMLStreamConstants.END_ELEMENT, staxDecoder.next()); + } + public static void main(String[] args) throws Exception { StAXCoderTestCase st = new StAXCoderTestCase("StAX");