All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.lolhens.edifact.Edifact.scala Maven / Gradle / Ivy

The newest version!
package de.lolhens.edifact

import fastparse.NoWhitespace._
import fastparse._

object Edifact {

  case class ServiceStringAdvice(componentSeparatorChar: Char,
                                 elementSeparatorChar: Char,
                                 decimalMarkChar: Char,
                                 releaseChar: Char,
                                 segmentTerminatorChar: Char)

  object ServiceStringAdvice {
    final val tag = "UNA"

    val default: ServiceStringAdvice = ServiceStringAdvice(':', '+', '.', '?', '\'')
  }

  case class Element(value: String)

  case class Composite(elements: List[Element]) {
    override def toString: String =
      s"Composite(${elements.map(_.value).mkString(", ")})"
  }

  case class Segment(tag: String,
                     composites: List[Composite]) {
    override def toString: String =
      s"Segment($tag, ${composites.mkString(", ")})"
  }

  case class Message(header: Segment,
                     trailer: Segment,
                     segments: List[Segment]) {
    override def toString: String = {
      s"""Message(
         |  header = $header,
         |  trailer = $trailer,
         |  segments = List(${segments.map("\n    " + _).mkString(",")}
         |  )
         |)""".stripMargin
    }
  }

  object Message {
    final val headerTag = "UNH"
    final val trailerTag = "UNT"
  }

  case class GroupEnvelope(header: Segment,
                           trailer: Segment)

  case class Group(envelope: Option[GroupEnvelope],
                   messages: List[Message]) {
    override def toString: String = {
      s"""Group(
         |  envelope = $envelope,
         |  messages = List(${messages.map(_.toString.split('\n').map("\n    " + _).mkString).mkString(",")}
         |  )
         |)""".stripMargin
    }
  }

  object Group {
    final val headerTag = "UNG"
    final val trailerTag = "UNE"
  }

  case class Envelope(serviceStringAdvice: ServiceStringAdvice,
                      header: Segment,
                      trailer: Segment,
                      groups: List[Group]) {
    override def toString: String = {
      s"""Envelope(
         |  serviceStringAdvice = $serviceStringAdvice,
         |  header = $header,
         |  trailer = $trailer,
         |  groups = List(${groups.map(_.toString.split('\n').map("\n    " + _).mkString).mkString(",")}
         |  )
         |)""".stripMargin
    }
  }

  object Envelope {
    final val headerTag = "UNB"
    final val trailerTag = "UNZ"
  }

  private case class Parser(serviceStringAdvice: ServiceStringAdvice) {

    import Parser._

    private val componentSeparator = serviceStringAdvice.componentSeparatorChar.toString
    private val elementSeparator = serviceStringAdvice.elementSeparatorChar.toString
    private val release = serviceStringAdvice.releaseChar.toString
    private val segmentTerminator = serviceStringAdvice.segmentTerminatorChar.toString

    def elementReservedChar[$: P]: P[Unit] = P {
      CharPred((componentSeparator + elementSeparator + segmentTerminator).contains(_))
    }

    def elementChar[$: P]: P[String] = P {
      release ~ elementReservedChar.! |
        !elementReservedChar ~ AnyChar.!
    }

    def elementString[$: P]: P[String] = P {
      elementChar.rep.map(e => e.mkString)
    }

    def composite[$: P]: P[Composite] = P {
      elementString.rep(sep = componentSeparator).map { elements =>
        Composite(elements.map(Element).toList)
      }
    }

    def segmentReservedTags[$: P]: P[Unit] = P {
      StringIn(
        ServiceStringAdvice.tag,
        Message.headerTag,
        Message.trailerTag,
        Group.headerTag,
        Group.trailerTag,
        Envelope.headerTag,
        Envelope.trailerTag
      )
    }

    def segmentTag[$: P]: P[String] = P {
      !segmentReservedTags ~ elementString
    }

    def segment[$: P](tag: => P[String] = null): P[Segment] = P {
      (Option(tag).getOrElse(segmentTag) ~ (elementSeparator ~/ composite).rep).map {
        case (tag, composites) =>
          Segment(tag, composites.toList)
      } ~ segmentTerminator ~ s.rep
    }

    def message[$: P]: P[Message] = P {
      (segment(Message.headerTag.!) ~/
        segment().rep ~
        segment(Message.trailerTag.!)).map {
        case (header, messages, trailer) =>
          Message(header, trailer, messages.toList)
      }
    }

    def group[$: P]: P[Group] = P {
      (segment(Group.headerTag.!) ~/
        message.rep ~
        segment(Group.trailerTag.!)).map {
        case (header, messages, trailer) =>
          Group(Some(GroupEnvelope(header, trailer)), messages.toList)
      }
    }

    def envelope[$: P]: P[Envelope] = P {
      (segment(Envelope.headerTag.!) ~/
        (group | message.map(message => Group(None, List(message)))).rep ~
        segment(Envelope.trailerTag.!)).map {
        case (header, groups, trailer) =>
          Envelope(serviceStringAdvice, header, trailer, groups.toList)
      }
    }
  }

  private object Parser {
    def s[$: P]: P[Unit] = CharPred(_.isWhitespace)

    def serviceStringAdvice[$: P]: P[ServiceStringAdvice] = P {
      ServiceStringAdvice.tag ~/ (AnyChar.rep(exactly = 4).! ~ " " ~ AnyChar.!).map { una =>
        val List(
        componentSeparator,
        elementSeparator,
        decimalMark,
        releaseCharacter,
        segmentTerminator
        ) = (una._1 + una._2).toList

        ServiceStringAdvice(
          componentSeparatorChar = componentSeparator,
          elementSeparatorChar = elementSeparator,
          decimalMarkChar = decimalMark,
          releaseChar = releaseCharacter,
          segmentTerminatorChar = segmentTerminator
        )
      } ~ s.rep
    }

    def parser[$: P]: P[Envelope] = P {
      Start ~
        (serviceStringAdvice ~/ "").?
          .map(_.getOrElse(ServiceStringAdvice.default))
          .flatMap(Parser(_).envelope) ~
        End
    }
  }

  def fromString(string: String): Envelope = {
    parse[Envelope](string, Parser.parser(_)).get.value
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy