Я использую синтаксический анализатор SAX, включенный в java, и заметил кое-что, что не понимаю / считаю раздражающим.
Я использую синтаксический анализатор SAX для запуска сотен XML-документов, где на самом деле нужно проанализировать только некоторые из них. Если первый элемент в документе не имеет правильного пространства имен, я просто прервусь и перейду к следующему документу.
Но на запуск документа требуется от 200 до 600 мсек, прежде чем он даже начнет читать. Я не мог понять почему, пока случайно не отключил интернет во время разработки и получил множество этого исключения:
java.net.UnknownHostException: hibernate.sourceforge.net
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
at sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
at sun.net.www.http.HttpClient.New(HttpClient.java:339)
at sun.net.www.http.HttpClient.New(HttpClient.java:357)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1220)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050)
at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:984)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:647)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1304)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1270)
at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:264)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1161)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1045)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:959)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:842)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:327)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:195)
at dk.magenta.alfresco.GenerateJavaMojo$Finder.find(GenerateJavaMojo.java:188)
at dk.magenta.alfresco.GenerateJavaMojo$Finder.visitFile(GenerateJavaMojo.java:215)
at dk.magenta.alfresco.GenerateJavaMojo$Finder.visitFile(GenerateJavaMojo.java:160)
at java.nio.file.Files.walkFileTree(Files.java:2670)
at java.nio.file.Files.walkFileTree(Files.java:2742)
at dk.magenta.alfresco.GenerateJavaMojo.execute(GenerateJavaMojo.java:110)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Таким образом, возникает двоякий вопрос: почему синтаксический анализатор sax все это время тратит на подключение к веб-URL, и могу ли я его выключить, или есть реализация, в которой я могу его отключить?
Обновлять: Я пробовал добавить такой EntityResolver.
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
SAXParser saxParser = factory.newSAXParser();
saxParser.getXMLReader().setEntityResolver(new DummyEntityResolver());
....
public class DummyEntityResolver implements EntityResolver {
public InputSource resolveEntity(String publicID, String systemID)
throws SAXException {
return new InputSource(new StringReader(""));
}
}
Никакого эффекта. Продолжительность звонков по-прежнему составляет в среднем 400 мсек и почти мгновенно, когда Интернет недоступен.
У многих есть и то, и другое. Я в основном разбираю XML-файлы в кучу зависимостей JAR, которая включает МНОЖЕСТВО Spring JAR.




Документы, вероятно, содержат ссылку на внешний DTD, хранящийся в этом месте. Если внешнее DTD содержит сущности, которые необходимо раскрыть, анализ без него может оказаться невозможным, но если вы знаете, что это не так, или если у вас есть локальная копия DTD, вы можете установить EntityResolver на синтаксический анализатор XML, который перенаправляет ссылки на локальный файл. Если вы не хотите писать свой собственный EntityResolver, вы также можете использовать каталог Oasis для перенаправления ссылок на локальные копии, но если вы не боитесь писать какую-либо Java, которая более сложна в настройке.
А нет возможности просто полностью отключить проверку DTD? На самом деле, если бы я мог просто отключить проверку DTD для первого элемента, а затем снова включить ее, это было бы идеально. Обычно я проверяю первый элемент только для того, чтобы решить, нужно ли мне анализировать файл.
Отключение проверки не приводит к отключению чтения DTD, потому что DTD используется не для проверки, а для других целей: в частности, для расширения сущности.
Итак, если я хочу иметь возможность просто посмотреть на первый тег без веб-вызовов, я полагаю, вы говорите, что мне придется выполнить некоторую предварительную проверку без использования анализатора XML вообще? Я привязан к нечестивой сфере анализа XML-файла как строки?
Я посоветовал установить EntityResolver на свой XML-синтаксический анализатор, похоже, вы игнорируете этот совет.
Нет, у меня есть установка EntitiyResolver, и это не повлияет. Я обновлю вопрос.
Возможно, вам потребуется установить какой-либо инструмент сетевого мониторинга (например, Charles), чтобы увидеть, какие ресурсы извлекаются из Интернета, чтобы вы могли узнать, откуда поступают звонки.
Конечно, синтаксический анализатор тратит время на подключение к Интернету для загрузки внешних DTD. Поскольку эти XML-файлы взяты из стандартных публичных библиотек, которые уже прошли проверку, я рекомендую вам отключить проверку с помощью:
SAXParserFactory saxParserFactory=SAXParserFactory.getInstance();
saxParserFactory.setValidating(false);
SAXParser saxParser=saxParserFactory.newSAXParser();
Отключения проверки обычно недостаточно, чтобы предотвратить чтение DTD, потому что DTD также используется для раскрытия сущности.
Я могу подтвердить, что вызова #setValidating (false) недостаточно. Наблюдается то же поведение, а это означает, что для завершения вызовов по-прежнему требуется 400 мс, если я не отключу подключение к Интернету.
Есть ли у этих XML-файлов какие-либо объявления DTD, XSD или XSL? Образец XML может помочь.