Java Validator блокирует файл при сбое - что я делаю неправильно? - PullRequest
6 голосов
/ 17 ноября 2011

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

Я использую метод javax.xml.validation.Validator и validate(). Это кажется достаточно простым и хорошо, когда проверка проходит. Я могу только предположить, что мне что-то не хватает при обработке ошибок, но API для Validator, похоже, не предоставляет ничего полезного. Кто-нибудь может пролить свет на то, что я здесь делаю неправильно?

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

Спасибо

Phil


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.URI;
import java.util.Scanner;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class ValidationTest {

    public static void validate(URI xmlLocation, URI schemaLocation) throws Exception {

        SchemaFactory schemaFactory = SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" );

        Source schemaSource = new StreamSource(schemaLocation.toString());
        Schema schema = schemaFactory.newSchema(schemaSource);

        Validator schemaValidator = schema.newValidator();

        StreamSource source = new StreamSource(xmlLocation.getPath());
        schemaValidator.validate( source );
    }


    public static void main(String[] args) throws Exception {
        File srcFile = new File("c:/aaa/MySrc-Broken.xml");
        File schema = new File("c:/aaa/MyStructureDefinition.xsd");

        try {
            ValidationTest.validate(srcFile.toURI(), schema.toURI());
        } catch(Exception e) {
            System.err.println(e);
        }

        // Use a Scanner to pause the thread, so that I can 
        // go and check the file's permissions.
        Scanner scan = new Scanner(System.in);
        scan.nextLine();
    }
}


Обновление:

У меня есть хак, который предоставляет (плохое) решение. Я добавляю собственный errorHandler в schemaValidator. Этот errorHandler просто сохраняет любые ошибки в переменной-члене. Это означает, что валидатор всегда будет успешным и, таким образом, снимет все блокировки входного файла. Однако затем я должен проверить обработчик ошибок, чтобы увидеть, были ли какие-либо ошибки, а затем выдать ошибку, если они были. Это не здорово, но помогает мне решить эту проблему.

Ответы [ 3 ]

3 голосов
/ 03 января 2012

Обратите внимание, что экземпляры StreamSource недопустимы.(http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/Validator.html)

URL xmlFileURL = xmlFileToCheck.toURI().toURL();
InputStream inputStream = xmlFileURL.openStream();
InputSource is = new InputSource(inputStream);
SAXSource saxSource = new SAXSource(is);

xmlValidator.validate(saxSource);

inputStream.close(); // this is probably important...
1 голос
/ 17 ноября 2011

перехватите исключение, возникшее в вашем вызове validate (), закройте объект StreamSource, связанный с вашим файлом, чтобы освободить файловые ресурсы, а затем сгенерируйте исключение до вашего вызывающего метода.

edit: youможет потребоваться явное извлечение InputStream, чтобы закрыть дескриптор основного файла - похоже, StreamSource не определяет явный способ закрытия основного потока.Проверьте, получите ли вы объект InputStream, возвращенный source.getInputStream () - если это так, закрытие этого должно освободить все основные дескрипторы вашего файла.

0 голосов
/ 03 января 2012

Валидатор не имеет возможности закрыть Source.Это может быть единственной причиной , что вы не должны использовать StreamSource с методом validate(). (Но могут быть и другие, поэтому вы можете пересмотреть свой подход.)

Приложение должно взять на себя ответственность за закрытие потоков.Чтобы быть уверенным, что это произойдет, вы можете использовать блок finally.

public static void validate(URI xmlLocation, URI schemaLocation) 
  throws Exception 
{
  SchemaFactory schemaFactory = 
    SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" );
  InputStream sIn = schemaLocation.toURL().openStream();
  try {
    Source schemaSource = new StreamSource(sIn, schemaLocation.toString());
    Schema schema = schemaFactory.newSchema(schemaSource);
    Validator schemaValidator = schema.newValidator();
    InputStream xIn = xmlLocation.toURL().openStream();
    try {
      StreamSource source = new StreamSource(xIn, xmlLocation.toString());
      schemaValidator.validate( source );
    } finally {
      xIn.close();
    }
  } finally {
    sIn.close();
  }
}
...