Scala/Java не соблюдает спецификации w3 «избыточного трафика dtd»?

StackOverflow https://stackoverflow.com/questions/1096285

  •  11-09-2019
  •  | 
  •  

Вопрос

Я новичок в Scala, поэтому, возможно, я не в курсе этого, я хочу знать, не в моем ли коде проблема.Учитывая файл Scala httpparse, упрощенный до:

object Http {
   import java.io.InputStream;
   import java.net.URL;

   def request(urlString:String): (Boolean, InputStream) =
      try {
         val url = new URL(urlString)
         val body = url.openStream
         (true, body)
      }
      catch {
         case ex:Exception => (false, null)
      }
}

object HTTPParse extends Application {
   import scala.xml._;
   import java.net._;

   def fetchAndParseURL(URL:String) = {
      val (true, body) = Http request(URL)
      val xml = XML.load(body) // <-- Error happens here in .load() method
      "True"
   }
}

Который запускается (URL не имеет значения, это пример шутки):

scala> HTTPParse.fetchAndParseURL("http://stackoverflow.com")

Результат неизменно:

   java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/html4/strict.dtd
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1187)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:973)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEnti...

Я видел Поток переполнения стека по этому поводу в отношении Java, а также Запись в блоге системной группы W3C о том, чтобы не пытаться получить доступ к этому DTD через Интернет.Я также изолировал ошибку в методе XML.load(), который, насколько я могу судить, является методом библиотеки Scala.

Мой вопрос:Как я могу это исправить? Является ли это побочным продуктом моего кода (списанного из Сообщение Рафаэля Феррейры), побочный продукт чего-то специфичного для Java, к которому мне нужно обратиться, как в предыдущая тема, или что-то специфическое для Scala?Где происходит этот вызов и является ли это ошибкой или особенностью?("Это мне?Это она, да?»)

Это было полезно?

Решение 5

Оно работает.После некоторой детективной работы, подробности, насколько я могу выяснить:

Пытаясь разобрать разрабатываемый RESTful-интерфейс, я собираю парсер и получаю вышеуказанную (скорее аналогичную) ошибку.Я пробую различные параметры, чтобы изменить вывод XML, но получаю ту же ошибку.Пытаюсь подключиться к XML-документу, который быстро накручиваю (списанному тупо из самого интерфейса) и получаю ту же ошибку.Затем я пытаюсь подключиться к чему угодно, просто так, и получаю ту же (опять же, скорее всего, только похожую) ошибку.

Я начал задаваться вопросом, была ли это ошибка в источниках или программе, поэтому я начал искать, и это похоже на постоянную проблему - со многими обращениями Google и SO по одной и той же теме.К сожалению, это заставило меня сосредоточиться на восходящих (языковых) аспектах ошибки, а не на устранении неполадок в самих источниках.

Перенесемся вперед, и парсер внезапно заработает на оригинальный XML-вывод.Я подтвердил, что на стороне сервера была проделана дополнительная работа (просто сумасшедшее совпадение?).У меня нет более раннего XML, но я подозреваю, что это связано с изменением идентификаторов документов.

Теперь парсер отлично работает с интерфейсом RESTful, а также с любым хорошо отформатированным XML, который я могу ему передать.Это также не работает на всех XHTML DTD, которые я пробовал (например.www.w3.org).Это противоречит ожиданиям @SeanReilly, но, похоже, согласуется с что утверждает W3.

Я все еще новичок в Scala, поэтому не могу определить, особый ли у меня случай или типичный.Я также не могу быть уверен, что эта проблема не возникнет у меня снова в другой форме в будущем.Кажется, что вытягивание XHTML будет продолжать вызывать эту ошибку, если вы не используете решение, подобное тем, которые были предложены @GClaramunt $ @J-16 SDiZ.Я не достаточно квалифицирован, чтобы знать, является ли это проблемой языка или моей реализацией решения (вероятно, позднее)

Я подозреваю, что в ближайшем будущем лучшим решением для меня было бы убедиться, что это было возможный проанализировать этот источник XML - вместо того, чтобы видеть, что у других была такая же ошибка, и предполагать, что с языком возникла функциональная проблема.

Надеюсь, это поможет другим.

Другие советы

Я столкнулся с ОДНОЙ проблемой и не нашел элегантного решения (я подумываю опубликовать вопрос в списке рассылки Scala). Тем временем я нашел обходной путь:реализуйте свой собственный SAXParserFactoryImpl, чтобы вы могли установить f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", истинный);свойство.Хорошо, что это не требует каких-либо изменений кода в базе кода Scala (хотя я согласен, что это следует исправить).Сначала я расширяю фабрику парсера по умолчанию:

package mypackage;

public class MyXMLParserFactory extends SAXParserFactoryImpl {
      public MyXMLParserFactory() throws SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException {
        super();
        super.setFeature("http://xml.org/sax/features/validation", false);
        super.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); 
        super.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); 
        super.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
      } 
    }

Ничего особенного, я просто хочу получить возможность установить свойство.

(Примечание:что это простой Java-код, скорее всего, то же самое можно написать и на Scala)

И в вашем коде Scala вам необходимо настроить JVM для использования вашей новой фабрики:

System.setProperty("javax.xml.parsers.SAXParserFactory", "mypackage.MyXMLParserFactory");

Затем вы можете вызвать XML.load без проверки.

Не обращаясь на данный момент к проблеме, что вы ожидаете, если запрос функции вернет false ниже?

def fetchAndParseURL(URL:String) = {      
  val (true, body) = Http request(URL)

Что воля случается, что будет выброшено исключение.Хотя можно было бы переписать это так:

def fetchAndParseURL(URL:String) = (Http request(URL)) match {      
  case (true, body) =>      
    val xml = XML.load(body)
    "True"
  case _ => "False"
}

Теперь, чтобы исправить проблему с анализом XML, мы отключим загрузку DTD в анализаторе, как предлагали другие:

def fetchAndParseURL(URL:String) = (Http request(URL)) match {      
  case (true, body) =>
    val f = javax.xml.parsers.SAXParserFactory.newInstance()
    f.setNamespaceAware(false)
    f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    val MyXML = XML.withSAXParser(f.newSAXParser())
    val xml = MyXML.load(body)
    "True"
  case _ => "False"
}

Теперь я поместил этот материал MyXML в fetchAndParseURL, чтобы сохранить структуру примера как можно более неизменной.Для реального использования я бы выделил его в объект верхнего уровня и превратил «парсер» в def вместо val, чтобы избежать проблем с изменяемыми парсерами:

import scala.xml.Elem
import scala.xml.factory.XMLLoader
import javax.xml.parsers.SAXParser
object MyXML extends XMLLoader[Elem] {
  override def parser: SAXParser = {
    val f = javax.xml.parsers.SAXParserFactory.newInstance()
    f.setNamespaceAware(false)
    f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    f.newSAXParser()
  }
}

Импортируйте пакет, в котором он определен, и все готово.

Решение GClaramunt сотворило для меня чудеса.Мое преобразование Scala выглядит следующим образом:

package mypackage
import org.xml.sax.{SAXNotRecognizedException, SAXNotSupportedException}
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
import javax.xml.parsers.ParserConfigurationException

@throws(classOf[SAXNotRecognizedException])
@throws(classOf[SAXNotSupportedException])
@throws(classOf[ParserConfigurationException])
class MyXMLParserFactory extends SAXParserFactoryImpl() {
    super.setFeature("http://xml.org/sax/features/validation", false)
    super.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
    super.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false)
    super.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
}

Как упоминалось в исходном посте, необходимо где-то поместить в код следующую строку:

System.setProperty("javax.xml.parsers.SAXParserFactory", "mypackage.MyXMLParserFactory")

Это проблема скалы.В встроенной Java есть возможность отключить загрузку DTD:

f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

В Scala нет аналогов.

Если вы хотите исправить это самостоятельно, проверьте scala/xml/parsing/FactoryAdapter.scala и вставьте строку

278   def loadXML(source: InputSource): Node = {
279     // create parser
280     val parser: SAXParser = try {
281       val f = SAXParserFactory.newInstance()
282       f.setNamespaceAware(false)

<-- вставьте сюда

283       f.newSAXParser()
284     } catch {
285       case e: Exception =>
286         Console.err.println("error: Unable to instantiate parser")
287         throw e
288     }

Есть две проблемы с тем, что вы пытаетесь сделать:

  • Анализатор xml Scala пытается физически получить DTD, хотя это не следует делать.У J-16 SDiZ, кажется, есть несколько советов по этой проблеме.
  • Страница переполнения стека, которую вы пытаетесь проанализировать, не является XML.Это строгий HTML4.

Вторую проблему на самом деле невозможно решить в вашем Scala-коде.Даже если вы решите проблему dtd, вы обнаружите, что исходный код не является допустимым XML (например, пустые теги не закрываются должным образом).

Вам придется либо проанализировать страницу с помощью чего-то помимо синтаксического анализатора XML, либо исследовать, используя такую ​​​​утилиту, как tidy, для преобразования html в xml.

Мои знания Scala довольно скудны, но не могли бы вы использовать Построение парсера вместо?

  val xml = new java.io.File("xmlWithDtd.xml")
  val parser = scala.xml.parsing.ConstructingParser.fromFile(xml, true)
  val doc = parser.document()
  println(doc.docElem)

Для scala 2.7.7 мне удалось сделать это с помощью scala.xml.parsing.XhtmlParser.

Настройка переключателей Xerces работает только в том случае, если вы используете Xerces.Распознаватель сущностей работает для любого парсера JAXP.

Существуют более обобщенные преобразователи сущностей, но эта реализация помогает, когда все, что я пытаюсь сделать, — это проанализировать действительный XHTML.

http://code.google.com/p/java-xhtml-cache-dtds-entityresolver/

Показывает, насколько просто кэшировать DTD и отказаться от сетевого трафика.

В любом случае это как я это исправлю.Я всегда забываю.Я всегда получаю ошибку.Я всегда иду за этим преобразователем сущностей.Тогда я снова в деле.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top