br.gov.lexml.renderer.docx.renderers.Renderers.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lexml-renderer-docx Show documentation
Show all versions of lexml-renderer-docx Show documentation
Renders LexML Brazil XML files to DOCX format.
The newest version!
package br.gov.lexml.renderer.docx.renderers
import cats.implicits._
import cats.data._
import br.gov.lexml.renderer.docx.docxmodel.builders._
import br.gov.lexml.renderer.docx.docxmodel.builders.implicits._
import br.gov.lexml.doc._
import br.gov.lexml.renderer.docx.docxmodel.{Table => DocxTable, _}
import java.net.URI
import org.apache.commons.io.IOUtils
import org.slf4j._
import br.gov.lexml.doc.xml.XmlConverter.SomeLexmlDocument
import br.gov.lexml.renderer.docx.LexmlToDocxConfig
import scala.language.existentials
trait ParRendererState[T <: ParRendererState[T]] {
def getBase : Option[URI]
def setBase(base : Option[URI]) : T
def addRef(href : URI) : (T,HrefData)
def getHyperlinkRPr : Option[RPr]
def addUnsupported(msg : String, elem : Any) : T
def currentRPrStyle : Option[RPr]
def setCurrentRPrStyle(rPr : Option[RPr]) : T
def endnoteId(origId : String) : String
def skipHyperlink : Boolean
}
trait RunRendererState[T <: RunRendererState[T]] {
def currentRPrStyle : Option[RPr]
}
trait MainDocRendererState[T <: MainDocRendererState[T]] {
def omissisParStyle : Option[PPr]
def addUnsupported(msg : String, elem : Any) : T
def nomeAgrupadorPredefPPrStyle(tipo : TipoAgrupadorPredef) : Option[PPr]
def rotuloAgrupadorPredefPPrStyle(tipo : TipoAgrupadorPredef) : Option[PPr]
def nomeAgrupadorPredefRPrStyle(tipo : TipoAgrupadorPredef) : Option[RPr]
def nomeAgrupadorPredefIniciaisMaiusc(tipo : TipoAgrupadorPredef) : Boolean
def rotuloAgrupadorPredefRPrStyle(tipo : TipoAgrupadorPredef) : Option[RPr]
def epigrafeParStyle : Option[PPr]
def epigrafeCharStyle : Option[RPr]
def ementaParStyle : Option[PPr]
def ementaCharStyle : Option[RPr]
def preambuloParStyle : Option[PPr]
def preambuloCharStyle : Option[RPr]
def formulaPromulgacaoParStyle : Option[PPr]
def formulaPromulgacaoCharStyle : Option[RPr]
def textoAlteracaoRPrStyle : Option[RPr]
def setBase(baseUri : Option[URI]) : T
def indentAlteracao : Ind
def rotuloStyleRPrForDispositivo(t : TipoDispositivo) : Option[RPr]
def contentStyleRPrForDispositivo(t : TipoDispositivo) : Option[RPr]
def contentStylePPrForDispositivo(t : TipoDispositivo) : Option[PPr]
def tituloStylePPrForDispositivo(t : TipoDispositivo) : Option[PPr]
def tituloStyleRPrForDispositivo(t : TipoDispositivo) : Option[RPr]
def localDataFechoStylePPr : Option[PPr]
def localDataFechoStyleRPr : Option[RPr]
def assinaturaTextoStylePPr : Option[PPr]
def assinaturaTextoStyleRPr : Option[RPr]
def notaReferenciadaRPrStyle : Option[RPr]
}
abstract sealed class RenderElement(superClasses_ : RenderElement*) extends Product {
val superClasses : Set[RenderElement] = if (superClasses_.isEmpty) { Set(RE_Any) } else { superClasses_.to(Set) }
def apply[T](m : Map[RenderElement,T]) : Option[T] =
get(m).headOption.map(_._2)
final def get[T](m : Map[RenderElement,T]) : IndexedSeq[(Int,T)] =
m.get(this).map(x => (0,x)).to(IndexedSeq) ++
superClasses.to(IndexedSeq).flatMap(_.get(m)).map(x => (x._1 + 1, x._2)).sortBy(_._1)
}
case object RE_Any extends RenderElement(Seq() :_*) {
override val superClasses : Set[RenderElement] = Set()
}
case object RE_ParteInicial extends RenderElement
case object RE_NomesAgrupador extends RenderElement
case object RE_RotulosAgrupador extends RenderElement
case object RE_Remissao extends RenderElement
case object RE_Omissis extends RenderElement
final case class RE_NomeAgrupador(t : TipoAgrupadorPredef) extends RenderElement(RE_NomesAgrupador)
final case class RE_RotuloAgrupador(t : TipoAgrupadorPredef) extends RenderElement(RE_RotulosAgrupador)
case object RE_Epigrafe extends RenderElement(RE_ParteInicial)
case object RE_Ementa extends RenderElement(RE_ParteInicial)
case object RE_Preambulo extends RenderElement(RE_ParteInicial)
case object RE_FormulaPromulgacao extends RenderElement(RE_ParteInicial)
case object RE_RotulosDispositivo extends RenderElement
final case class RE_RotuloDispositivo(t : TipoDispositivo) extends RenderElement(RE_RotulosDispositivo)
case object RE_ConteudosDispositivo extends RenderElement
final case class RE_ConteudoDispositivo(t : TipoDispositivo) extends RenderElement(RE_ConteudosDispositivo)
case object RE_TitulosDispositivo extends RenderElement
final case class RE_TituloDispositivo(t : TipoDispositivo) extends RenderElement(RE_TitulosDispositivo)
case object RE_TextoAlteracao extends RenderElement
case object RE_AbrevArtigo extends RenderElement(RE_RotulosDispositivo)
case object RE_LocalDataFecho extends RenderElement
case object RE_AssinaturaTexto extends RenderElement
case object RE_NotaReferenciada extends RenderElement
object RenderElementMap {
}
final case class Constants(
hrefIdPrefix : String = "HrefId",
pprStyles : Map[RenderElement,PPr] = Map(),
rprStyles : Map[RenderElement,RPr] = Map(),
indentAlteracao : Ind = Ind(),
spacingAlteracao : Spacing = Spacing(),
iniciaisMaiusculas : Set[RenderElement] = Set(),
expressoesEmBold : Set[String] = Set(),
skipHyperlink : Boolean = false
)
object Constants {
lazy val default = Constants(
pprStyles = Map(
RE_Ementa -> DefaultStyles.pprEmenta,
RE_Epigrafe -> DefaultStyles.pprEpigrafe,
RE_Preambulo -> DefaultStyles.pprPreambulo,
RE_Omissis -> DefaultStyles.pprOmissis,
RE_NomesAgrupador -> DefaultStyles.pprNomeAgrupador,
RE_RotulosAgrupador -> DefaultStyles.pprRotuloAgrupador,
RE_Any -> DefaultStyles.pprAny,
RE_ConteudosDispositivo -> DefaultStyles.pprConteudoDispositivo,
RE_TitulosDispositivo -> DefaultStyles.pprTituloDispositivo,
RE_LocalDataFecho -> DefaultStyles.pprLocalDataFecho,
RE_AssinaturaTexto -> DefaultStyles.pprAssinaturaTexto,
RE_FormulaPromulgacao -> DefaultStyles.pprFormulaPromulgacao
),
rprStyles = Map(
//RE_TextoAlteracao -> RPr(),
//RE_Remissao -> RPr()
RE_NomesAgrupador -> DefaultStyles.rprNomeAgrupador,
RE_NomeAgrupador(TAP_Secao) -> DefaultStyles.rprSecaoSubsecao,
RE_NomeAgrupador(TAP_Subsecao) -> DefaultStyles.rprSecaoSubsecao,
RE_RotulosAgrupador -> DefaultStyles.rprRotuloAgrupador,
RE_RotuloAgrupador(TAP_Secao) -> DefaultStyles.rprRotuloSecaoSubsecao,
RE_RotuloAgrupador(TAP_Subsecao) -> DefaultStyles.rprRotuloSecaoSubsecao,
RE_Ementa -> DefaultStyles.rprEmenta,
RE_Epigrafe -> DefaultStyles.rprEpigrafe,
RE_Preambulo -> DefaultStyles.rprPreambulo,
RE_Remissao -> DefaultStyles.rprLinkRemissao,
RE_TituloDispositivo(TDP_Artigo) -> DefaultStyles.rprTituloArtigo,
RE_LocalDataFecho -> DefaultStyles.rprLocalDataFecho,
RE_AssinaturaTexto -> DefaultStyles.rprAssinaturaTexto,
RE_FormulaPromulgacao -> DefaultStyles.rprFormulaPromulgacao,
RE_NotaReferenciada -> DefaultStyles.rprNotaReferenciada
),
indentAlteracao = DefaultStyles.indentAlteracao1,
spacingAlteracao = DefaultStyles.spacingAlteracao1,
iniciaisMaiusculas = Set(
RE_NomeAgrupador(TAP_Secao),
RE_NomeAgrupador(TAP_Subsecao)
),
expressoesEmBold = Set[String](
"(?i)caput",
"(?i)in fine", "(?i)quorum",
"(?i)libor", "(?i)price", "(?i)front-end fee",
"(?i)transaction fee",
"(?i)variable spread loan",
"(?i)spread"
).map(x => "\\b" + x + "\\b") ++
Set("^O PRESIDENTE DA REP[UÚ]BLICA",
"^O PRESIDENTE DO CONGRESSO",
"^O Presidente da República(?= decreta:)",
"^DECRETA: *$",
"^Pre[âa]mbulo$")
)
}
final case class RendererState(
base : Option[URI] = None,
hrefNext : Int = 1,
hrefToHrefData : Map[URI,HrefData] = Map(),
unsupportedCases : Seq[(String,Any)] = Seq(),
currentRPrStyle : Option[RPr] = None,
endnoteRefs : Set[String] = Set(),
constants : Constants = Constants(),
endnoteIdMap : Map[String,String] = Map()
) extends ParRendererState[RendererState]
with MainDocRendererState[RendererState]
with RunRendererState[RendererState] {
override def getBase = base
override def setBase(b : Option[URI]) = copy(base = b)
override def addRef(href : URI) =
hrefToHrefData.get(href) match {
case Some(data) => (this,data)
case None =>
val idNum = hrefNext
val id = constants.hrefIdPrefix + idNum
val data = HrefData(href=href,id=id)
(copy(hrefToHrefData = hrefToHrefData + (href -> data), hrefNext = hrefNext + 1),data)
}
def mapGetConsiderDefault[K,V](m : Map[K,V],k : K) : Option[V] = {
m.get(k).orElse {
try { Some(m(k)) } catch { case _ : Exception => None }
}
}
override def getHyperlinkRPr : Option[RPr] = RE_Remissao(constants.rprStyles)
override def addUnsupported(msg : String, elem : Any) =
copy(unsupportedCases = unsupportedCases :+ ((msg,elem)))
override def setCurrentRPrStyle(rPr : Option[RPr]) =
copy(currentRPrStyle = rPr)
override def omissisParStyle = RE_Omissis(constants.pprStyles)
override def nomeAgrupadorPredefPPrStyle(tipo : TipoAgrupadorPredef) =
RE_NomeAgrupador(tipo)(constants.pprStyles)
override def rotuloAgrupadorPredefPPrStyle(tipo : TipoAgrupadorPredef) =
RE_RotuloAgrupador(tipo)(constants.pprStyles)
override def nomeAgrupadorPredefRPrStyle(tipo : TipoAgrupadorPredef) =
RE_NomeAgrupador(tipo)(constants.rprStyles)
override def rotuloAgrupadorPredefRPrStyle(tipo : TipoAgrupadorPredef) =
RE_RotuloAgrupador(tipo)(constants.rprStyles)
override def epigrafeParStyle = constants.pprStyles.get(RE_Epigrafe)
override def epigrafeCharStyle = constants.rprStyles.get(RE_Epigrafe)
override def ementaParStyle = constants.pprStyles.get(RE_Ementa)
override def ementaCharStyle = constants.rprStyles.get(RE_Ementa)
override def preambuloParStyle = constants.pprStyles.get(RE_Preambulo)
override def preambuloCharStyle = constants.rprStyles.get(RE_Preambulo)
override def formulaPromulgacaoParStyle = constants.pprStyles.get(RE_FormulaPromulgacao)
override def formulaPromulgacaoCharStyle = constants.rprStyles.get(RE_FormulaPromulgacao)
override def textoAlteracaoRPrStyle = constants.rprStyles.get(RE_TextoAlteracao)
override def indentAlteracao = constants.indentAlteracao
override def rotuloStyleRPrForDispositivo(t : TipoDispositivo) = RE_RotuloDispositivo(t)(constants.rprStyles)
override def contentStyleRPrForDispositivo(t : TipoDispositivo) = RE_ConteudoDispositivo(t)(constants.rprStyles)
override def contentStylePPrForDispositivo(t : TipoDispositivo) = RE_RotuloDispositivo(t)(constants.pprStyles)
override def nomeAgrupadorPredefIniciaisMaiusc(tipo : TipoAgrupadorPredef) =
constants.iniciaisMaiusculas.contains(RE_NomeAgrupador(tipo))
override def tituloStylePPrForDispositivo(t : TipoDispositivo) = RE_TituloDispositivo(t)(constants.pprStyles)
override def tituloStyleRPrForDispositivo(t : TipoDispositivo) = RE_TituloDispositivo(t)(constants.rprStyles)
override def localDataFechoStylePPr = constants.pprStyles.get(RE_LocalDataFecho)
override def localDataFechoStyleRPr = constants.rprStyles.get(RE_LocalDataFecho)
override def assinaturaTextoStylePPr = constants.pprStyles.get(RE_AssinaturaTexto)
override def assinaturaTextoStyleRPr = constants.rprStyles.get(RE_AssinaturaTexto)
override def notaReferenciadaRPrStyle = constants.rprStyles.get(RE_NotaReferenciada)
override def endnoteId(origId : String) : String =
endnoteIdMap(origId)
override def skipHyperlink = constants.skipHyperlink
}
object RendererState {
implicit val mergeable = new Mergeable2[RendererState,RendererState] {
override def merge(a : RendererState, b : RendererState) =
RendererState(
base = a.base,
hrefNext = b.hrefNext,
hrefToHrefData = b.hrefToHrefData,
unsupportedCases = b.unsupportedCases,
currentRPrStyle = a.currentRPrStyle,
constants = a.constants,
endnoteRefs = a.endnoteRefs ++ b.endnoteRefs,
endnoteIdMap = a.endnoteIdMap ++ b.endnoteIdMap)
def extract(a : RendererState) = a
}
}
class Renderers(config : LexmlToDocxConfig) extends RunBuilderOps[RendererState] with ParBuilderOps[RendererState]
with DocxCompSeqBuilderOps[RendererState] {
val logger = LoggerFactory.getLogger("br.gov.lexml.renderer.docx.renderers")
type RunRenderer[A] = PB[A]
type ParRenderer[A] = MB[A]
import RendererState.mergeable
def rotulo(r : Rotulo, rPr : Option[RPr] = None, extraSpace : Boolean = false) : RunRenderer[Unit] = {
val suffix = if (extraSpace) { " " } else { "" }
runM_(rPr)(text(r.rotulo + suffix))
}
def omissis : RunRenderer[Unit] = {
runM_()(tab)
}
def parOmissis(x : Omissis) : ParRenderer[Unit] =
aspasP(x.abreAspas,x.fechaAspas,x.notaAlteracao) {
for {
style <- inspectMDState(_.omissisParStyle)
_ <- parM(style)(omissis)
} yield ()
}
def agrupadorGenerico(ag : AgrupadorGenerico) : ParRenderer[Unit] =
modifyMDState(_.addUnsupported("agrupadorGenerico: não suportado: ",ag))
def agrupadorPredef(ag : AgrupadorPredef) : ParRenderer[Unit] =
aspasP(ag.abreAspas,ag.fechaAspas,ag.notaAlteracao) {
for {
nomeAgrupadorPPrStyle <- inspectMDState(_.nomeAgrupadorPredefPPrStyle(ag.tipoAgrupador))
nomeAgrupadorRPrStyle <- inspectMDState(_.nomeAgrupadorPredefRPrStyle(ag.tipoAgrupador))
rotuloAgrupadorPPrStyle <- inspectMDState(_.rotuloAgrupadorPredefPPrStyle(ag.tipoAgrupador))
rotuloAgrupadorRPrStyle <- inspectMDState(_.rotuloAgrupadorPredefRPrStyle(ag.tipoAgrupador))
iniciaisMaiusc <- inspectMDState(_.nomeAgrupadorPredefIniciaisMaiusc(ag.tipoAgrupador))
_ <- ag.rotulo.ifDef(x => parM(rotuloAgrupadorPPrStyle)(
rotulo(x,rotuloAgrupadorRPrStyle)
))
_ <- ag.nomeAgrupador.ifDef(x => parM(nomeAgrupadorPPrStyle)(
withStyleRunRenderer(nomeAgrupadorRPrStyle)(
inlineSeq(x.inlineSeq)
)))
} yield ()
} .flatMap { _ => mapM_(ag.elems)(hierarchicalElement) }
def agrupador(ag : Agrupador) : ParRenderer[Unit] = ag match {
case x : AgrupadorPredef => agrupadorPredef(x)
case x : AgrupadorGenerico => agrupadorGenerico(x)
}
def hierarchicalElement(he : HierarchicalElement) : ParRenderer[Unit] = he match {
case x : Agrupador => agrupador(x)
case x : Artigo => artigo(x)
case x : Omissis => parOmissis(x)
}
def remissaoMultipla(r : RemissaoMultipla) : RunRenderer[Unit] =
for {
oldBase <- inspectPState(_.getBase)
newBase = oldBase.map(_.resolve(r.base.uri)).orElse(Some(r.base.uri))
_ <- modifyPState(_.setBase(newBase))
_ <- inlineSeq(r.inlineSeq)
_ <- modifyPState(_.setBase(oldBase))
} yield ()
def remissao(r : Remissao) : RunRenderer[Unit] = /* for {
base <- inspectPState(_.getBase)
href = base.map(_.resolve(r.href.uri)).getOrElse(r.href.uri)
hd <- modifyPStateV(_.addRef(href))
rPr <- inspectPState(_.getHyperlinkRPr)
_ <- withStyleRunRenderer(rPr)(hyperlink(id = Some(hd.id),anchor=hd.anchor,tooltip=hd.tooltip)(inlineSeq(r.inlineSeq)))
} yield (()) */ for {
sh <- inspectPState(_.skipHyperlink)
_ <-
if (!sh) { for {
base <- inspectPState(_.getBase)
href = base.map(_.resolve(r.href.uri)).getOrElse(r.href.uri)
lexmlPortalLink = new java.net.URL(config.getLinkTemplate.format(href)).toURI
hd <- modifyPStateV(_.addRef(lexmlPortalLink))
rPr <- inspectPState(_.getHyperlinkRPr)
_ <- withStyleRunRenderer(rPr)(hyperlink(id = Some(hd.id),anchor=hd.anchor,tooltip=hd.tooltip)(inlineSeq(r.inlineSeq)))
} yield () } else { inlineSeq(r.inlineSeq) }
} yield ()
def articulacao(a : Articulacao) : ParRenderer[Unit] =
mapM_(a.elems)(hierarchicalElement)
def formulaPromulgacao(e : FormulaPromulgacao) : ParRenderer[Unit] =
aspasP(e.abreAspas,e.fechaAspas,e.notaAlteracao)(
for {
pPr <- inspectMDState(_.formulaPromulgacaoParStyle)
rPr <- inspectMDState(_.formulaPromulgacaoCharStyle)
_ <- mapM_(e.inlineSeqs)(x => parM(pPr)(withStyleRunRenderer(rPr)(inlineSeq(x.inlineSeq))))
} yield (()))
def epigrafe(e : Epigrafe) : ParRenderer[Unit] =
aspasP(e.abreAspas,e.fechaAspas,e.notaAlteracao)(
for {
pPr <- inspectMDState(_.epigrafeParStyle)
rPr <- inspectMDState(_.epigrafeCharStyle)
_ <- parM(pPr)(withStyleRunRenderer(rPr)(inlineSeq(e.inlineSeq)))
} yield (()))
def ementa(e : Ementa) : ParRenderer[Unit] =
aspasP(e.abreAspas,e.fechaAspas,e.notaAlteracao)(
for {
pPr <- inspectMDState(_.ementaParStyle)
rPr <- inspectMDState(_.ementaCharStyle)
_ <- parM(pPr)(withStyleRunRenderer(rPr)(inlineSeq(e.inlineSeq)))
} yield (()))
def preambulo(pb : Preambulo) : ParRenderer[Unit] =
aspasP(pb.abreAspas,pb.fechaAspas,pb.notaAlteracao)(
mapM_(pb.inlineSeqs)(preambuloLine))
def preambuloLine(pl : PreambuloLine) : ParRenderer[Unit] =
for {
pPr <- inspectMDState(_.preambuloParStyle)
rPr <- inspectMDState(_.preambuloCharStyle)
_ <- parM(pPr)(withStyleRunRenderer(rPr)(inlineSeq(pl.inlineSeq)))
} yield (())
def genHtmlInlineElement(ge : GenHtmlInlineElement) : RunRenderer[Unit] =
ge.tipoHtmlInlineElement match {
case TGHIE_B => boldened(inlineSeq(ge.inlineSeq))
case TGHIE_I => italicized(inlineSeq(ge.inlineSeq))
case TGHIE_Sub => inSubscript(inlineSeq(ge.inlineSeq))
case TGHIE_Sup => inSuperscript(inlineSeq(ge.inlineSeq))
case TGHIE_Ins => insertion(ge)
case TGHIE_Del => deletion(ge)
case TGHIE_Dfn => definition(ge)
}
def runWithRPrChange[A](f : RPr => RPr)(rr : RunRenderer[A]) : RunRenderer[A] =
for {
rPr <- inspectPState(_.currentRPrStyle)
rPr1 = f(rPr.getOrElse(RPr()))
_ <- modifyPState(_.setCurrentRPrStyle(Some(rPr1)))
res <- rr
_ <- modifyPState(_.setCurrentRPrStyle(rPr))
} yield (res)
def boldened[T](rr : RunRenderer[T]) : RunRenderer[T] =
runWithRPrChange(_.copy(bold = Some(true)))(rr)
def italicized[T](rr : RunRenderer[T]) : RunRenderer[T] =
runWithRPrChange(_.copy(italics = Some(true)))(rr)
def inSubscript[T](rr : RunRenderer[T]) : RunRenderer[T] =
runWithRPrChange(_.copy(vertAlign = Some(VA_Subscript)))(rr)
def inSuperscript[T](rr : RunRenderer[T]) : RunRenderer[T] =
runWithRPrChange(_.copy(vertAlign = Some(VA_Superscript)))(rr)
def insertion(x : GenHtmlInlineElement) : RunRenderer[Unit] =
modifyPState(_.addUnsupported("insertion(GenHtmlInlineElement)",x))
def deletion(x : GenHtmlInlineElement) : RunRenderer[Unit] =
modifyPState(_.addUnsupported("deletion(GenHtmlInlineElement)",x))
def definition(x : GenHtmlInlineElement) : RunRenderer[Unit] =
modifyPState(_.addUnsupported("definition(GenHtmlInlineElement)",x))
def htmlInlineElement(hie : HTMLinlineElement) : RunRenderer[Unit] = hie match {
case x : Anchor => anchor(x)
case x : Span => span(x)
case x : GenHtmlInlineElement => genHtmlInlineElement(x)
}
def lxInlineElement(e : LXInlineElement) : RunRenderer[Unit] = e match {
case x : Remissao => remissao(x)
case x : RemissaoMultipla => remissaoMultipla(x)
case x => modifyPState(_.addUnsupported("lxInlineElement: não suportado",x))
}
def inlineElement(ie : InlineElement) : RunRenderer[Unit] = ie match {
case nr : NotaReferenciada => notaReferenciada(nr)
case ie : LXInlineElement => lxInlineElement(ie)
case hie: HTMLinlineElement => htmlInlineElement(hie)
case x => modifyPState(_.addUnsupported("lxInlineElement: não suportado",x))
}
def notaReferenciada(nr : NotaReferenciada) : RunRenderer[Unit] = for {
//rPr <- inspectPState(_.notaReferenciadaRPrStyle)
id <- inspectPState(_.endnoteId(nr.nota.id))
rPr <- inspectPState(_.currentRPrStyle)
_ <- runM(rPr)(text("("))
_ <- runM(rPr)(endnoteReference(id))
_ <- runM(rPr)(text(")"))
} yield ()
def inlineSeq(il : InlineSeq) : RunRenderer[Unit] = {
val rr = mixed(il.mixedElems)
il.lang.map(l => inLang(l.code)(rr)).getOrElse(rr)
}
def mixed(m : Mixed[InlineElement]) : RunRenderer[Unit] = mixedWith[InlineElement](m,inlineElement)
def mixedWith[A](m : Mixed[A], f : A => RunRenderer[Unit]) : RunRenderer[Unit] = for {
rPr <- inspectPState(_.currentRPrStyle)
_ <- mapM_(m.elems)(x => x match {
case Left(data) => f(data)
case Right(txt : String) => runM_(rPr)(text(txt))
})
} yield (())
def inLang[A](lang : String)(rr : RunRenderer[A]) : RunRenderer[A] = {
modifyPState(_.addUnsupported("inLang: não suportado",lang)) .flatMap(_ => rr)
}
def projetoNorma(pj : ProjetoNorma) : ParRenderer[Unit] = norma(pj.norma)
def norma(norma : Norma) : ParRenderer[Unit] = hierarchicalStructure(norma.contents)
def hierarchicalStructure(hs : HierarchicalStructure) : ParRenderer[Unit] = {
for {
_ <- hs.formulaPromulgacao.ifDef(formulaPromulgacao)
_ <- hs.epigrafe.ifDef(epigrafe)
_ <- hs.ementa.ifDef(ementa)
_ <- hs.preambulo.ifDef(preambulo)
_ <- articulacao(hs.articulacao)
_ <- hs.localDataFecho.ifDef(localDataFecho)
_ <- mapM_(hs.assinaturas)(assinatura)
} yield (())
}
def lexmlDocument(doc : SomeLexmlDocument) : ParRenderer[Unit] = {
documentContents(doc.contents)
}
def documentContents(contents : DocumentContents[T] forSome { type T <: DocumentContents[T] }) : ParRenderer[Unit] = contents match {
case n : Norma => norma(n)
case pj : ProjetoNorma => projetoNorma(pj)
case x => modifyMDState(_.addUnsupported("documentContents: não suportado",x))
}
def parTexto(rPr : Option[RPr] = None)(txt : String) : ParRenderer[Unit] =
parM()(runM_(rPr)(text(txt)))
def alteracao(a : Alteracao) : ParRenderer[Unit] = {
val baseUri = a.base.map(_.uri)
for {
rPrTexto <- inspectMDState(_.textoAlteracaoRPrStyle)
ind <- inspectMDState(_.indentAlteracao)
_ <- modifyMDState(_.setBase(baseUri))
inside = mapM_(a.mixedElems.elems)(_.fold(alteracaoElement,parTexto(rPrTexto))) : ParRenderer[Unit]
_ <- indenting(ind)(inside)
_ <- modifyMDState(_.setBase(None))
} yield (())
}
def addIndent(indent : Ind, p : P) : P = {
val pPr = p.pPr.orElse(Some(PPr())).map { ppr => ppr.copy(ind = Some(indent)) }
p.copy(pPr = pPr)
}
def addIndents(indent : Ind, elems : Seq[DocxTextComponent]) : Seq[DocxTextComponent] =
elems.collect {
case p : P => addIndent(indent,p)
case x => x
}
def indenting[T](indent : Ind)(pr : ParRenderer[T]) : ParRenderer[T] = State { st =>
val st1 = st.copy(contents = Seq())
val (st2,res) = pr.run(st1).value
val comps = st2.contents
val comps1 : Seq[DocxTextComponent] = st.contents ++ addIndents(indent,comps)
(st2.copy(contents = comps1),res)
}
def alteracaoElement(a : AlteracaoElement) : ParRenderer[Unit] = {
val inside = a match {
case x : BlockElement => blockElement(x)
case x : Container => container(x)
case x : FormulaPromulgacao => formulaPromulgacao(x)
case x : Epigrafe => epigrafe(x)
case x : Ementa => ementa(x)
case x : Preambulo => preambulo(x)
case x : HierarchicalElement => hierarchicalElement(x)
case x : LXContainer => lxContainer(x,false)
case _ => modifyMDState(_.addUnsupported("alteracaoElement: não suportado",a))
}
inside
//aspasP(a.abreAspas,a.fechaAspas,a.notaAlteracao)(inside)
}
def lxContainer(lc : LXContainer,skipFirst : Boolean) : ParRenderer[Unit] = lc match {
case d : Dispositivo => dispositivo(d,skipFirst)
case o : Omissis => if (skipFirst) { State.pure(()) } else { parOmissis(o) }
case _ => modifyMDState(_.addUnsupported("lxContainer: não suportado",lc))
}
def dispositivo(d : Dispositivo, skipFirst : Boolean) : ParRenderer[Unit] = d match {
case dg : DispositivoGenerico => dispositivoGenerico(dg,skipFirst)
case dn : DispositivoPredefNA => dispositivoPredefNA(dn,skipFirst)
case a : Artigo => artigo(a)
}
def dispositivoGenerico(d : DispositivoGenerico, skipFirst : Boolean) : ParRenderer[Unit] =
aspasP(d.abreAspas,d.fechaAspas,d.notaAlteracao) {
for {
rotuloRPr <- rPrRotuloForDispositivo(TDP_Pena,d.rotulo)
contentRPr <- inspectMDState(_.contentStyleRPrForDispositivo(TDP_Pena))
contentPPr <- inspectMDState(_.contentStylePPrForDispositivo(TDP_Pena))
(firstInlineSeq ,restInlineSeqs) = (d.conteudo match {
case None => (State.pure(()),List())
case Some(t : TextoDispositivo) => (
t.inlineSeqs.map(_.inlineSeq).headOption.ifDef(x => withStyleRunRenderer(contentRPr)(inlineSeq(x))),
t.inlineSeqs.tail.map(_.inlineSeq).to(List))
case Some(OmissisSimples) => (
omissis,
List())
}) : (RunRenderer[Unit], Seq[InlineSeq])
(head,tail) /* : (ParRenderer[Unit],Seq[InlineSeq]) */ = (if(!skipFirst) {
val r1 = d.rotulo.ifDef(x => rotulo(x,rotuloRPr,true))
val c1 = firstInlineSeq
val l1 = parM(contentPPr)(r1 >> c1)
(l1,restInlineSeqs)
} else {
(State.pure(()),restInlineSeqs)
}) : (ParRenderer[Unit],Seq[InlineSeq])
rendPar = (p : InlineSeq) =>
parM(contentPPr)(withStyleRunRenderer(contentRPr)(inlineSeq(p)))
tail1 = mapM_(tail)(rendPar)
firstPart = head.flatMap { _ => mapM_(tail)(rendPar) }
_ <- firstPart
_ <- d.alteracao.ifDef(alteracao)
_ <- mapM_(d.containers){x => lxContainer(x,false) }
} yield (())
}
// modifyMDState(_.addUnsupported("dispositivoGenerico: não suportado",dg))
def anchor(a : Anchor) : RunRenderer[Unit] =
modifyPState(_.addUnsupported("anchor: não suportado: ",a))
def span(s : Span) : RunRenderer[Unit] =
remissao(Remissao(href=s.href,inlineSeq=s.inlineSeq))
def withStyleRunRenderer[E](rPr : Option[RPr] = None)(rr : RunRenderer[E]) : RunRenderer[E] =
for {
st <- inspectPState(_.currentRPrStyle)
_ <- modifyPState(_.setCurrentRPrStyle(mergeRPr(st,rPr)))
res <- rr
_ <- modifyPState(_.setCurrentRPrStyle(st))
} yield (res)
def mergeRPr(r1 : Option[RPr],r2 : Option[RPr]) : Option[RPr] = {
r1.flatMap(x => r2.flatMap(y => Some(x + y)).orElse(Some(x))).orElse(r2)
}
def rPrRotuloForDispositivo(t : TipoDispositivoPredef,r : Option[Rotulo]) : ParRenderer[Option[RPr]] =
inspectMDState(_.rotuloStyleRPrForDispositivo(t))
/* for {
rotuloRPr <- inspectMDState(_.rotuloStyleRPrForDispositivo(t))
rPr = t match {
case TDP_Paragrafo if r.map(_.rotulo.trim.contains("nico")).getOrElse(false) =>
Some(rotuloRPr.getOrElse(RPr()).copy(italics = Some(true), bold = Some(true)))
case _ => rotuloRPr
}
} yield (rPr) */
def dispositivoPredefNA(d : DispositivoPredefNA,skipFirst : Boolean) : ParRenderer[Unit] =
aspasP(d.abreAspas,d.fechaAspas,d.notaAlteracao) {
for {
rotuloRPr <- rPrRotuloForDispositivo(d.tipoDispositivo,d.rotulo)
contentRPr <- inspectMDState(_.contentStyleRPrForDispositivo(d.tipoDispositivo))
contentPPr <- inspectMDState(_.contentStylePPrForDispositivo(d.tipoDispositivo))
(firstInlineSeq ,restInlineSeqs) = (d.conteudo match {
case None => (State.pure(()),List())
case Some(t : TextoDispositivo) => (
t.inlineSeqs.map(_.inlineSeq).headOption.ifDef(x => withStyleRunRenderer(contentRPr)(inlineSeq(x))),
t.inlineSeqs.tail.map(_.inlineSeq).to(List))
case Some(OmissisSimples) => (
omissis,
List())
}) : (RunRenderer[Unit], Seq[InlineSeq])
(head,tail) /* : (ParRenderer[Unit],Seq[InlineSeq]) */ = (if(!skipFirst) {
val r1 = d.rotulo.ifDef(x => rotulo(x,rotuloRPr,true))
val c1 = firstInlineSeq
val l1 = parM(contentPPr)(r1 >> c1)
(l1,restInlineSeqs)
} else {
(State.pure(()),restInlineSeqs)
}) : (ParRenderer[Unit],Seq[InlineSeq])
rendPar = (p : InlineSeq) =>
parM(contentPPr)(withStyleRunRenderer(contentRPr)(inlineSeq(p)))
tail1 = mapM_(tail)(rendPar)
firstPart = head.flatMap { _ => mapM_(tail)(rendPar) }
tituloPPr <- inspectMDState(_.tituloStylePPrForDispositivo(TDP_Artigo/*d.tipoDispositivo*/))
tituloRPr <- inspectMDState(_.tituloStyleRPrForDispositivo(TDP_Artigo/*d.tipoDispositivo*/))
_ <- d.titulo.ifDef(t => parM(tituloPPr)(withStyleRunRenderer(tituloRPr)(inlineSeq(t.inlineSeq))))
_ <- firstPart
_ <- d.alteracao.ifDef(alteracao)
_ <- mapM_(d.containers){x => lxContainer(x,false) }
} yield (())
}
def renderDispHead(
pPr : Option[PPr] = None,
rotuloRPr : Option[RPr] = None,
r : Option[Rotulo],
conteudo : Option[RunRenderer[Unit]]) :
ParRenderer[Unit] = {
parM(pPr)( for {
_ <- r.ifDef{rot => rotulo(rot,rotuloRPr,true)}
_ <- conteudo.ifDef(x => x)
} yield ()
)
}
private val rotuloArtigoPattern = """(^[aA]rt\.)\s+(\S+)""".r
private val rotuloArtigoUnicoPattern = """^artigo\s\+[uú]nico""".r
def rotuloArtigo(r : Rotulo) : RunRenderer[Unit] = {
val rPrArtigoUnico = Some(RPr(bold = Some(true), italics = Some(true)))
val rPrLabelRotuloArtigo = Some(RPr(bold = Some(true)))
val rPrNumRotuloArtigo = None
r.rotulo.toLowerCase.trim match {
case rotuloArtigoUnicoPattern() =>
runM_(rPrArtigoUnico)(text(r.rotulo))
case _ => r.rotulo.trim match {
case rotuloArtigoPattern(label,num) =>
runM_(rPrLabelRotuloArtigo)(text(label + " ")) .flatMap (_ =>
runM_(rPrNumRotuloArtigo)(text(num + " ")))
case _ =>
modifyPState(_.addUnsupported("rótulo de artigo",r)).flatMap (_ =>
runM_(rPrNumRotuloArtigo)(text(r.rotulo)))
}
}
}
def artigo(a : Artigo) : ParRenderer[Unit] = {
this.ensuring(a.tipoDispositivo != null)
val rotuloArt = a.rotulo.ifDef(rotuloArtigo)
val selectFirst = ({
case t : TextoDispositivo => (inlineSeq(t.inlineSeqs.head.inlineSeq),true)
case OmissisSimples => (omissis,true)
} : PartialFunction[ConteudoDispositivo,(RunRenderer[Unit],Boolean)])
val (conteudo,skipFirst,contFechaAspas,contNotaAlteracao) = (a.containers.head match {
case d : DispositivoPredefNA if d.tipoDispositivo == TDP_Caput =>
val (ct,skip) = d.conteudo.collect(selectFirst).getOrElse((State.pure(()),false)) : (RunRenderer[Unit],Boolean)
(ct,skip,d.fechaAspas,d.notaAlteracao)
case _ => (State.pure(()),false,false,None)
}) : (RunRenderer[Unit],Boolean,Boolean,Option[String])
aspasP(a.abreAspas,a.fechaAspas,a.notaAlteracao)(for {
rotuloRPr <- inspectMDState(_.rotuloStyleRPrForDispositivo(a.tipoDispositivo))
contentRPr <- inspectMDState(_.contentStyleRPrForDispositivo(a.tipoDispositivo))
contentPPr <- inspectMDState(_.contentStylePPrForDispositivo(a.tipoDispositivo))
tituloArtigoPPr <- inspectMDState(_.tituloStylePPrForDispositivo(a.tipoDispositivo))
tituloArtigoRPr <- inspectMDState(_.tituloStyleRPrForDispositivo(a.tipoDispositivo))
_ <- a.titulo.ifDef(t => parM(tituloArtigoPPr)(withStyleRunRenderer(tituloArtigoRPr)(inlineSeq(t.inlineSeq))))
_ <- aspasP(false,contFechaAspas,contNotaAlteracao) { parM(contentPPr) { rotuloArt.flatMap(_ => conteudo.flatMap(_ => State.pure(()))) } }
_ <- a.containers.headOption.ifDef(x => lxContainer(x,skipFirst))
_ <- mapM_(a.containers.tail){x => lxContainer(x,false) }
} yield ()
)
}
def localDataFecho(ldf : LocalDataFecho) : ParRenderer[Unit] = for {
localDataFechoPPr <- inspectMDState(_.localDataFechoStylePPr)
localDataFechoRPr <- inspectMDState(_.localDataFechoStyleRPr)
_ <- mapM_(ldf.inlineSeqs)(x => parM(localDataFechoPPr)(withStyleRunRenderer(localDataFechoRPr)(inlineSeq(x.inlineSeq))))
} yield (())
def assinatura(assinatura : ParteFinalAssinatura) : ParRenderer[Unit] = assinatura match {
case x: ElementoAssinaturaGrupo => elementoAssinaturaGrupo(x)
case ag: AssinaturaGrupo => State.pure(())
}
def elementoAssinaturaGrupo(x : ElementoAssinaturaGrupo) : ParRenderer[Unit] = x match {
case at : AssinaturaTexto => for {
assinaturaTextoPPr <- inspectMDState(_.assinaturaTextoStylePPr)
assinaturaTextoRPr <- inspectMDState(_.assinaturaTextoStyleRPr)
_ <- mapM_(at.inlineSeqs)(x => parM(assinaturaTextoPPr)(withStyleRunRenderer(assinaturaTextoRPr)(inlineSeq(x.inlineSeq))))
} yield ()
case ax : Assinatura => State.pure(())
}
def blockElement(b : BlockElement) : ParRenderer[Unit] = b match {
case x : HTMLBlock => htmlBlock(x)
case _ => modifyMDState(_.addUnsupported("blockElement: não suportado: ",b))
}
def htmlBlock(b : HTMLBlock) : ParRenderer[Unit] = b match {
case x : Paragraph => paragraph(x)
case x : HTMLList => htmlList(x)
case x : Table => table(x)
case _ => modifyMDState(_.addUnsupported("htmlBlock: não suportado: ",b))
}
def paragraph(p : Paragraph) : ParRenderer[Unit] =
aspasP(p.abreAspas,p.fechaAspas,p.notaAlteracao)(parM()(inlineSeq(p.inlineSeq)))
def htmlList(hl : HTMLList) : ParRenderer[Unit] =
modifyMDState(_.addUnsupported("htmlList: não suportado: ",hl))
def table(t : Table) : ParRenderer[Unit] =
modifyMDState(_.addUnsupported("table: não suportado: ",t))
def container(e : Container) : ParRenderer[Unit] =
modifyMDState(_.addUnsupported("container: não suportado: ",e))
def aspasP[A](abreAspas : Boolean, fechaAspas : Boolean, notaAlteracao : Option[String])(rr : ParRenderer[A]) : ParRenderer[A] = State { st =>
val st0 = st.copy(contents = Seq())
val (st1,res) = rr.run(st0).value
val v2 = mergeable.merge(st.value,st1.value)
val elems = addAspasP(st1.contents,abreAspas,fechaAspas,notaAlteracao)
val st2 = st.copy(contents = st.contents ++ elems,value = v2)
(st2,res)
}
//TODO: Inserir nota de alteração
def addAspasP(els : Seq[DocxTextComponent],abreAspas : Boolean, fechaAspas : Boolean,
notaAlteracao : Option[String])
: Seq[DocxTextComponent] = {
if((abreAspas || fechaAspas || !notaAlteracao.isEmpty) && els.exists(_.isInstanceOf[P])) {
val (head,tail1) = els.span(!_.isInstanceOf[P])
val revTail1 = tail1.reverse
val (revTail,revMiddle) = revTail1.span(!_.isInstanceOf[P])
val tail = revTail.reverse
val middle = revMiddle.reverse.collect { case x : P => x }
val middle1 = if(abreAspas) { insertAbreAspas(middle.head) +: middle.tail } else middle
val last1 = middle1.last
val last2 = if (fechaAspas) { last1.insertLast(fechaAspasRun) } else { last1 }
val last3 = notaAlteracao.map { x =>
val r = R(contents = Seq(T(s" (${x.trim})",preserveSpace=true)))
last2.insertLast(r)
}.getOrElse(last2)
val middle2 = if(fechaAspas) { middle1.init :+ last3 } else { middle1 }
val res = head ++ middle2 ++ tail
res
} else { els }
}
val abreAspasRun : R = R(contents = Seq(T("“")))
val fechaAspasRun : R = R(contents = Seq(T("”")))
def insertAbreAspas(p : P) : P = p.insertFirst(abreAspasRun)
def insertFechaAspas(p : P) : P = p.insertLast(fechaAspasRun)
def runM_(rPr : Option[RPr] = None)(rr : RB[Unit]) : PB[Unit] =
for {
rPr1 <- inspectPState(_.currentRPrStyle)
rPr2 = mergeRPr(rPr1, rPr)
_ <- runM(rPr2)(rr)
} yield (())
}
final case class MainDocRendererResult(
docx : Docx,
unsupportedCases : Seq[(String,Any)])
class WordMarker(regex : String, change : RPr => RPr) {
import br.gov.lexml.renderer.docx.docxmodel._
val exprRe = regex.r
def fRunContentContainer(x : RunContent) : Seq[RunContent] = x match {
case x : ParElementContainer[RunContent] => Seq(x.flatMap(fParElementContainer))
case x : RunContentContainer[RunContent] => Seq(x.flatMap(fRunContentContainer))
case x => Seq(x)
}
def trimLeft(rc : RunContent) : RunContent = rc match {
case t : T => t.copy(text = t.text.replaceAll("^\\p{Space}+",""))
case x => x
}
def hasTrailingSpace(rc : RunContent) : Boolean = rc match {
case t : T => t.text.matches("\\p{Space}$")
case x => false
}
def fParElementContainer(before : Option[ParElement],x : ParElement, next: Option[ParElement]) : Seq[ParElement] = x match {
case x : R => {
val l : Seq[Either[(T,Seq[(Int,Int)]),RunContent]] = x.contents.collect {
case t : T =>
val matches = exprRe.findAllMatchIn(t.text).to(Seq).map { m =>
(m.start,m.end) }
if(matches.isEmpty) { Right(t) }
else { Left(t,matches) }
case t => Right(t)
}
var lastHadSpace : Boolean = false
val pl : Seq[ParElement] = l.flatMap {
case Right(t) =>
val t1 = if(lastHadSpace) { trimLeft(t) } else { t }
lastHadSpace = hasTrailingSpace(t1)
Seq(x.copy(contents = Seq(t1)))
case Left((t,matches)) => {
//DEBUG: start
val doDebug = false //t.text.startsWith("regimento interno")
def debug(msg : => String) = if (doDebug) { println("fParElementContainer: " + msg) } else { }
//DEBUG: end
debug(s"""t = ${t}, matches=${matches}, next = ${next}""")
val b = Seq.newBuilder[R]
var last : Int = 0
lazy val newRPr = Some(change(x.rPr.getOrElse(RPr())))
def passthrough(start : Int) : Unit = {
debug(s"""passthrough: start = ${start}, next = ${next}""")
val mayAddWSatEnd = start < t.text.length ||
next.isDefined
if(start > last) {
val t1 = t.text.substring(last,start)
val tb = Seq.newBuilder[T]
/*val tl = if(t1.charAt(0).isWhitespace && last > 0) {
tb += T(" ",preserveSpace=true)
}*/
val t2 = t1.replaceAll("\\p{Space}+$"," ")
.replaceAll(" +"," ")
debug(s"""t2 = "${t2}" """)
val t3 = if(lastHadSpace) { t2.replaceAll("^\\p{Space}+","") } else { t2 }
val t4 = if(mayAddWSatEnd) { t3 } else { t3.replaceAll("\\p{Space}$","") }
tb += T(t4, preserveSpace=true)
lastHadSpace = t4.matches("\\p{Space}$")
debug(s"""t4="${t4}" """)
/*if(mayAddWSatEnd && t2.last.isWhitespace) {
tb += T(" ",preserveSpace=true)
t
}*/
b += x.copy(contents = tb.result())
}
}
for {
(start,end) <- matches
} {
passthrough(start)
val mid = t.text.substring(start,end)
b += R(rPr = newRPr,contents = Seq(T(mid)))
last = end
}
passthrough(t.text.length)
b.result()
}
}
pl
}
case x : ParElementContainer[ParElement] => Seq(x.flatMap(fParElementContainer))
//case x : RunContentContainer[ParElement] => Seq(x.flatMap(fRunContentContainer))
case x => Seq(x)
}
def apply(x : DocxTextComponent) : Seq[DocxTextComponent] = x match {
case p : P => Seq(p.flatMap(fParElementContainer))
case x => Seq(x)
}
def apply(x : DocxMainDocument) : DocxMainDocument =
x.flatMap(apply)
}
object WordMarker {
def makeOr(exprs : Seq[String]) = exprs.map(x => "(?:" + x + ")").mkString("|")
val AddItalics : RPr => RPr = _.copy(italics = Some(true))
val AddBold : RPr => RPr = _.copy(bold = Some(true))
}
final case class MainDocRenderer(constants : Constants = Constants(), baseDocx : Docx = Docx(),
config : LexmlToDocxConfig) {
val st0 = RendererState(constants = constants, endnoteIdMap = Map("aaa" -> "bbb"))
val reformatRules : Seq[(String,RPr => RPr)] = Seq(
WordMarker.makeOr(constants.expressoesEmBold.to(Seq)) -> WordMarker.AddBold
)
val renderers = new Renderers(config)
def makeEndnotes(doc : SomeLexmlDocument, notas : Seq[(Int,Option[String],Nota)]) :
(Seq[(String,Seq[DocxTextComponent])],Seq[String],Map[String,String]) = {
val orphans = notas.collect { case (seq,None,_) => seq.toString }.to(Seq)
val endnotes = notas.map { case (seq,_,nota) =>
val contentsM = for {
_ <- mapM_(nota.contents)(renderers.paragraph)
} yield ()
val contents = contentsM.makeDocxCompSeq(st0).value._1
val contents1 = reformatRules.foldLeft(contents) { case (d,(regex,change)) =>
d.flatMap { x => new WordMarker(regex,change)(x) }
}
(seq.toString,contents1)
}
val idToSeq = notas.collect {
case (seq,Some(id),_) => (id,seq.toString)
case (seq,None,_) => (seq.toString,seq.toString)
}.toMap
(endnotes,orphans,idToSeq)
}
def render(doc : SomeLexmlDocument) : MainDocRendererResult = {
val notas = doc.metadado.notas.zipWithIndex.map { case (nota,idx) =>
(idx+1,nota.id,nota)
}
val (endnotes,orphans,idToSeq) = makeEndnotes(doc,notas)
val doc1 =
if(!orphans.isEmpty) {
doc.copy(contents = doc.contents.mapNorma { norma =>
val epigrafe = norma.contents.epigrafe.map { ep =>
val elems1 = ep.inlineSeq.mixedElems.elems ++
orphans.map { id => Left(NotaReferenciada(IDREF(id))) }
ep.copy(inlineSeq = ep.inlineSeq.copy(mixedElems = Mixed(elems1)))
}
norma.copy(contents = norma.contents.copy(epigrafe = epigrafe))
})
} else {
doc
}
val st0_1 = st0.copy(endnoteIdMap = idToSeq)
val (d,st1) = renderers.lexmlDocument(doc1).makeMainDoc(st0_1).value
val d1 = d.copy(d.contents.filterNot(_.isEmpty))
val d2 = reformatRules.foldLeft(d1) { case (d,(regex,change)) =>
new WordMarker(regex,change)(d)
}
val docx = baseDocx.copy(mainDoc = d2, hyperlinks = st1.hrefToHrefData.values.to(Seq),
endnotes = endnotes)
MainDocRendererResult(
docx=docx,
unsupportedCases = st1.unsupportedCases)
}
}
object PackageRenderer {
private def logger = LoggerFactory.getLogger(classOf[PackageRenderer])
type ReplaceFunc = Option[Array[Byte]] => Option[Array[Byte]]
def xmlToByteArray(e : scala.xml.Elem) = {
import java.io._
import scala.xml._
val w = new StringWriter()
XML.write(w,e,"utf-8",true,null,MinimizeMode.Always)
w.close()
w.toString().getBytes("utf-8")
}
}
class PackageRenderer(config : LexmlToDocxConfig) {
import PackageRenderer._
private lazy val referenceEntries = {
import java.io._
import java.util.zip._
val zis = new ZipInputStream(new ByteArrayInputStream(config.referenceDocx))
val b = Map.newBuilder[String,Array[Byte]]
var ze : ZipEntry = zis.getNextEntry()
while(ze != null) {
val data = IOUtils.toByteArray(zis)
b += (ze.getName -> data)
zis.closeEntry()
ze = zis.getNextEntry()
}
zis.close()
b.result()
}
private def writeReplace(transf : (String,ReplaceFunc)*) : Array[Byte] = {
import java.io._
import java.util.zip._
val m : Map[String,ReplaceFunc] =
transf.groupBy(_._1).view.mapValues { l =>
val l1 = l.map(_._2)
val f = l1.foldLeft((x => x) : ReplaceFunc) { case(sofar,f) => { x => sofar(f(x)) } }
f
}.toMap
//transf.toMap
val bos = new ByteArrayOutputStream()
val zos = new ZipOutputStream(bos)
val m1 = referenceEntries ++ m.flatMap{ case (k,f) =>
f(referenceEntries.get(k)).map(d => (k,d)) }
m1.foreach { case (name,data) =>
val ze = new ZipEntry(name)
ze.setSize(data.length)
zos.putNextEntry(ze)
zos.write(data)
zos.closeEntry()
}
zos.close()
bos.toByteArray
}
private lazy val stylesElem = DefaultStyles.styles.asXML // DocxMainPartRenderer.stylesElem
def render(doc : SomeLexmlDocument,
extraReplace : Seq[(String,PackageRenderer.ReplaceFunc)] = Seq()) : Array[Byte] = {
val baseDocx = Docx(
baseRelationships =
referenceEntries.get("word/_rels/document.xml.rels").map { f =>
Relationships.fromByteArray(f)
}.getOrElse(Relationships())
)
val renderer = new MainDocRenderer(Constants.default,baseDocx,config)
val res = renderer.render(doc)
res.unsupportedCases.foreach { case (msg,x) =>
logger.warn("Caso não suportado pelo renderer: " + msg + "\n" + x.toString)
}
def subst(v : Array[Byte]) : ReplaceFunc = _ => Some(v)
val files = res.docx.files
val replaceFuncs = files.view.mapValues { subst }.to(Seq) ++ extraReplace
writeReplace(replaceFuncs :_*)
}
}