diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 02713043a6..5f67aa54ea 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -32,7 +32,9 @@ import java.io.File; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import org.xml.sax.InputSource; /** * A tool for running the SBE parser, validator, and code generator. @@ -281,9 +283,16 @@ public static MessageSchema parseSchema(final String sbeSchemaFilename) .warningsFatal(Boolean.parseBoolean(System.getProperty(VALIDATION_WARNINGS_FATAL))) .suppressOutput(Boolean.parseBoolean(System.getProperty(VALIDATION_SUPPRESS_OUTPUT))); - try (InputStream in = new BufferedInputStream(Files.newInputStream(Paths.get(sbeSchemaFilename)))) + final Path filePath = Paths.get(sbeSchemaFilename); + try (InputStream in = new BufferedInputStream(Files.newInputStream(filePath))) { - return XmlSchemaParser.parse(in, optionsBuilder.build()); + final InputSource inputSource = new InputSource(in); + final Path parentPath = filePath.toAbsolutePath().getParent(); + if (parentPath != null) + { + inputSource.setSystemId(filePath.toUri().toString()); + } + return XmlSchemaParser.parse(inputSource, optionsBuilder.build()); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index a1f0dd5b88..08e494e7dd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -34,6 +34,7 @@ import java.nio.ByteOrder; import java.util.HashMap; import java.util.Map; +import org.xml.sax.InputSource; import static uk.co.real_logic.sbe.PrimitiveType.*; import static uk.co.real_logic.sbe.xml.Presence.REQUIRED; @@ -94,16 +95,16 @@ public static void validate(final String xsdFilename, final InputStream in, fina } /** - * Take an {@link InputStream} and parse it generating map of template ID to Message objects, types, and schema. + * Take an {@link InputSource} and parse it generating map of template ID to Message objects, types, and schema. *

* Exceptions are passed back up for any problems. * - * @param in stream from which schema is read. + * @param is inputSource from which schema is read. Ideally it will have the systemId property set to resolve relative references * @param options to be applied during parsing. * @return {@link MessageSchema} encoding for the schema. * @throws Exception on parsing error. */ - public static MessageSchema parse(final InputStream in, final ParserOptions options) throws Exception + public static MessageSchema parse(final InputSource is, final ParserOptions options) throws Exception { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -114,7 +115,7 @@ public static MessageSchema parse(final InputStream in, final ParserOptions opti factory.setFeature("http://apache.org/xml/features/xinclude/fixup-base-uris", false); } - final Document document = factory.newDocumentBuilder().parse(in); + final Document document = factory.newDocumentBuilder().parse(is); final XPath xPath = XPathFactory.newInstance().newXPath(); final ErrorHandler errorHandler = new ErrorHandler(options); @@ -133,6 +134,25 @@ public static MessageSchema parse(final InputStream in, final ParserOptions opti return messageSchema; } + /** + * Wraps an {@link InputStream} into an {@link InputSource} and delegates to + * {@link #parse(org.xml.sax.InputSource, uk.co.real_logic.sbe.xml.ParserOptions) }. + *

Note: this method does not the the {@link InputSource#setSystemId(java.lang.String) } property, however. It is recommended to use the + * {@link #parse(org.xml.sax.InputSource, uk.co.real_logic.sbe.xml.ParserOptions) } method directly.

+ * + *

+ * Exceptions are passed back up for any problems. + * + * @param in stream from which schema is read. + * @param options to be applied during parsing. + * @return {@link MessageSchema} encoding for the schema. + * @throws Exception on parsing error. + */ + public static MessageSchema parse(final InputStream in, final ParserOptions options) throws Exception + { + return parse(new InputSource(in), options); + } + /** * Scan XML for all types (encodedDataType, compositeType, enumType, and setType) and save in map * diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java new file mode 100644 index 0000000000..33b113055c --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013-2019 Real Logic Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import org.junit.Test; + +import org.xml.sax.InputSource; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class RelativeXIncludeTest +{ + @Test + public void shouldParseFileInSubDir() + throws Exception + { + final ClassLoader classLoader = getClass().getClassLoader(); + final URL testResource = classLoader.getResource("sub/basic-schema.xml"); + final InputStream inStream = testResource.openStream(); + final InputSource is = new InputSource(inStream); + + final File file = new File(testResource.getFile()); + is.setSystemId(file.toPath().toAbsolutePath().getParent().toUri().toString()); + parse(is, ParserOptions.DEFAULT); + } + +} \ No newline at end of file diff --git a/sbe-tool/src/test/resources/sub/basic-schema.xml b/sbe-tool/src/test/resources/sub/basic-schema.xml new file mode 100644 index 0000000000..54c728ca24 --- /dev/null +++ b/sbe-tool/src/test/resources/sub/basic-schema.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/sbe-tool/src/test/resources/sub/sub2/common.xml b/sbe-tool/src/test/resources/sub/sub2/common.xml new file mode 100644 index 0000000000..ddf42c9ca1 --- /dev/null +++ b/sbe-tool/src/test/resources/sub/sub2/common.xml @@ -0,0 +1,10 @@ + + + + + + + + + +