Как рекурсивно анализировать файлы xsd для создания списка включенных схем для инкрементной сборки в Maven? - PullRequest
1 голос
/ 24 февраля 2011

У меня есть проект Maven, который использует jaxb2-maven-plugin для компиляции некоторых файлов xsd.Он использует staleFile, чтобы определить, был ли изменен какой-либо из упомянутых schemaFiles.К сожалению, в рассматриваемых xsd-файлах используются теги <xs:include schemaLocation="../relative/path.xsd"/> для включения других файлов схемы, которые не указаны в аргументе schemaFile, поэтому вычисление staleFile в плагине не позволяет точно определить, когда нужно что-то перекомпилировать.Это приводит к разрушению инкрементных сборок по мере развития включенных схем.

Очевидно, что одним из решений было бы перечисление всех рекурсивно-ссылочных файлов в schemaFile выполнения.Тем не менее, будут случаи, когда разработчики не делают этого и не ломают сборку.Вместо этого я бы хотел каким-то образом автоматизировать создание этого списка.

Один из подходов, который приходит на ум, состоит в том, чтобы как-то проанализировать файлы XSD верхнего уровня, а затем либо задать свойство, либо вывести файл, которыйЗатем я могу передать параметр schemaFile или schemaFiles.Плагин Groovy gmaven, кажется, может быть естественным способом внедрить эту функциональность прямо в POM.Но я не достаточно знаком с Groovy, чтобы начать.

Может кто-нибудь предоставить пример кода?Или предложить альтернативную реализацию / решение?

Спасибо!

Ответы [ 2 ]

1 голос
/ 28 февраля 2011

Исходя из ответа tim_yates, следующее является работоспособным решением, которое вам, возможно, придется настраивать в зависимости от того, как вы конфигурируете плагин jaxb2.

Настройка gmaven-plugin выполнения в начале жизненного цикла (например, на этапе инициализации), которое выполняется со следующей конфигурацией ...

Начните с функции для сбора объектов File ссылочных схем (это уточнение ответа Тима):

def findRefs { f ->
    def relPaths = new XmlSlurper().parse(f).depthFirst().findAll {
        it.name()=='include'
    }*.@schemaLocation*.text()
    relPaths.collect { new File(f.absoluteFile.parent + "/" + it).canonicalFile }
}

Оберните это в функцию, которая перебирает результаты, пока не будут найдены все дочерние элементы:

def recursiveFindRefs = { schemaFiles ->
    def outputs = [] as Set
    def inputs  = schemaFiles as Queue
    // Breadth-first examine all refs in all schema files
    while (xsd = inputs.poll()) {
        outputs << xsd
        findRefs(xsd).each {
            if (!outputs.contains(it)) inputs.add(it)
        }
    }
    outputs
}

Настоящая магия приходит тогда, когда вы анализируете проект Maven, чтобы определить, что делать. Сначала найдите плагин JAXB:

jaxb = project.build.plugins.find { it.artifactId == 'jaxb2-maven-plugin' }

Затем проанализируйте каждое выполнение этого плагина (если у вас есть несколько). Код предполагает, что каждый набор выполнений schemaDirectory, schemaFiles и staleFile (т.е. не использует значения по умолчанию!) И что вы не используете schemaListFileName:

jaxb.executions.each { ex ->
    log.info("Processing jaxb execution $ex")
    // Extract the schema locations; the configuration is an Xpp3Dom
    ex.configuration.children.each { conf ->
        switch (conf.name) {
            case "schemaDirectory":
                schemaDirectory = conf.value
                break
            case "schemaFiles":
                schemaFiles = conf.value.split(/,\s*/)
                break
            case "staleFile":
                staleFile = conf.value
                break
        }
    }

Наконец, мы можем открыть schemaFiles, проанализировать их, используя функции, которые мы определили ранее:

    def schemaHandles = schemaFiles.collect { new File("${project.basedir}/${schemaDirectory}", it) }
    def allSchemaHandles = recursiveFindRefs(schemaHandles)

... и сравнить их время последнего изменения с временем изменения устаревшего файла, при необходимости отмените устаревший файл.

    def maxLastModified = allSchemaHandles.collect {
            it.lastModified()
        }.max()
    def staleHandle = new File(staleFile)
    if (staleHandle.lastModified() < maxLastModified) {
        log.info("  New schemas detected; unlinking $staleFile.")
        staleHandle.delete()
    }
}
1 голос
/ 25 февраля 2011

Не уверен, как бы вы интегрировали его в свою сборку Maven - Maven на самом деле не моя вещь: - (

Однако, если у вас есть путь к файлу xsd, вы сможете получить файлы, на которые он ссылается, выполнив что-то вроде:

def rootXsd = new File( 'path/to/xsd' )
def refs = new XmlSlurper().parse( rootXsd ).depthFirst().findAll { it.name()=='include' }.@schemaLocation*.text()
println "$rootXsd references $refs"

Итак, refs - это список строк, которые должны быть путями к включенному xsds

.
...