Skip to content

Commit

Permalink
Resumed work whose purpose I frankly don't recall
Browse files Browse the repository at this point in the history
The only thing I can say for sure is that the unit tests run.
I know it has to do with multi-extractors and in particular, the method in Extractors called seqExtractorByLabel, which seems to work (maybe).
  • Loading branch information
rchillyard committed May 7, 2023
1 parent 5f5a38a commit 7d889b5
Show file tree
Hide file tree
Showing 9 changed files with 692 additions and 91 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ xmlOutput.xml
/xmlOutput.kml

miniSampleOutput.kml

sampleOutput.kml
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
organization := "com.phasmidsoftware"

name := "KMLDoc"

version := "1.0"
Expand All @@ -17,7 +19,7 @@ libraryDependencies += scalaModules %% "scala-xml" % "2.1.0"

libraryDependencies ++= Seq(
"com.phasmidsoftware" %% "flog" % "1.0.8",
"ch.qos.logback" % "logback-classic" % "1.4.5" % "runtime",
"ch.qos.logback" % "logback-classic" % "1.4.6" % "runtime",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
"org.scalatest" %% "scalatest" % "3.2.15" % Test
)
51 changes: 32 additions & 19 deletions src/main/scala/com/phasmidsoftware/kmldoc/KML.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.phasmidsoftware.kmldoc

import com.phasmidsoftware.core.FP.tryNotNull
import com.phasmidsoftware.core.{Text, TryUsing, XmlException}
import com.phasmidsoftware.kmldoc.KmlRenderers.sequenceRendererFormatted
import com.phasmidsoftware.render._
Expand All @@ -9,8 +10,8 @@ import java.net.URL
import org.slf4j.{Logger, LoggerFactory}
import scala.io.Source
import scala.reflect.ClassTag
import scala.util.Success
import scala.util.matching.Regex
import scala.util.{Failure, Success, Try}
import scala.xml.{Elem, NamespaceBinding, XML}

/**
Expand Down Expand Up @@ -61,8 +62,10 @@ trait Feature extends KmlObject
* Companion object to Feature.
*/
object Feature extends Extractors with Renderers {
private val labels: Seq[String] = Seq("Folder", "Document", "Placemark")
implicit val multiExtractor: MultiExtractor[Seq[Feature]] =
lazyMultiExtractor(multiExtractor3[Feature, (Folder, Document, Placemark), Folder, Document, Placemark]((f, d, p) => (f, d, p), Seq("Folder", "Document", "Placemark")) ^^ "multiExtractorFeature")
lazyMultiExtractor(multiExtractor3[Feature, (Folder, Document, Placemark), Folder, Document, Placemark]((f, d, p) => (f, d, p), labels) ^^ "multiExtractorFeature")
implicit val seqExtractor: Extractor[Seq[Feature]] = seqExtractorByLabel("features", labels)
implicit val renderer: Renderable[Feature] = new Renderers {}.lazyRenderer(rendererSuper2[Feature, Placemark, Container] ^^ "rendererFeature")
implicit val seqRenderer: Renderable[Seq[Feature]] = sequenceRenderer[Feature] ^^ "rendererFeatures"
}
Expand Down Expand Up @@ -565,10 +568,13 @@ case class Coordinate(long: String, lat: String, alt: String)

object Coordinate {

private val longLatAlt: Regex = """\s*([\d\-\.]+),([\d\-\.]+),([\d\-\.]+)""".r
// CONSIDER using Parser-combinators here.
private val longLatAlt: Regex = """^\s*(((-)?(\d+(\.\d*)?)),\s*((-)?(\d+(\.\d*)?)),\s*((-)?(\d+(\.\d*)?)))\s*""".r

def apply(w: String): Coordinate = w match {
case longLatAlt(long, lat, alt) => Coordinate(long, lat, alt)
case longLatAlt(_, long, _, _, _, lat, _, _, _, alt, _, _, _) =>
println(s"$long, $lat, $alt")
Coordinate(long, lat, alt)
case _ => throw XmlException(s"bad coordinate string: $w")
}

Expand Down Expand Up @@ -819,6 +825,10 @@ object KML extends Extractors with Renderers {
case class KML_Binding(kml: KML, binding: NamespaceBinding)

object KML_Binding {
implicit val extractor: Extractor[KML_Binding] = Extractor {
node =>
implicitly[Extractor[KML]].extract(node) map (KML_Binding(_, node.scope))
}
implicit val renderer: Renderable[KML_Binding] = Renderable {
(t: KML_Binding, format: Format, stateR: StateR) =>
TryUsing(stateR.addAttribute(s"""${t.binding}"""))(rs => implicitly[Renderable[KML]].render(t.kml, format, rs))
Expand Down Expand Up @@ -849,25 +859,28 @@ object KmlRenderers extends Renderers {
// CONSIDER Rename as KML
object KMLCompanion {

val logger: Logger = LoggerFactory.getLogger(KML.getClass)
val logger: Logger = LoggerFactory.getLogger(KML.getClass)

// TESTME
def loadKML(resource: URL): KML = {
require(resource != null)
loadKML(resource.getPath)
}
// TESTME
def loadKML(resource: URL): Try[Seq[Feature]] = {
val z: Try[URL] = tryNotNull(resource)(s"resource $resource is null")
z flatMap (x => loadKML(x.getPath))
}

private def loadKML(file: String): KML = {
require(file != null)
val xml: Elem = XML.loadFile(file)
// val kmls: collection.Seq[KML] = for (kml <- xml \\ "kml") yield KML.fromXML(kml)
// kmls.head
KML(Nil)
}
private def loadKML(file: String): Try[Seq[Feature]] = {
require(file != null)
val xml: Elem = XML.loadFile(file)

val kys: Seq[Try[Seq[Feature]]] = for (kml <- xml \\ "kml") yield Extractor.extractAll[Seq[Feature]](kml)
kys.headOption match {
case Some(ky) => ky
case _ => Failure(new NoSuchElementException)
}
}
}

object Test extends App {
// TESTME -- it appears not to work.
val kml: KML = KMLCompanion.loadKML(KML.getClass.getResource("sample.kml"))
println(s"KML: $kml")
val kml: Try[Seq[Feature]] = KMLCompanion.loadKML(KML.getClass.getResource("sample.kml"))
kml foreach (fs => fs foreach (f => println(s"KML: $f")))
}
30 changes: 25 additions & 5 deletions src/main/scala/com/phasmidsoftware/xml/Extractor.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.phasmidsoftware.xml

import com.phasmidsoftware.core.Utilities.{lensFilter, renderNode, renderNodes}
import com.phasmidsoftware.core.Utilities.{lensFilter, renderNode, renderNodes, sequence}
import com.phasmidsoftware.core.XmlException
import com.phasmidsoftware.flog.Flog
import com.phasmidsoftware.xml.Extractors.{extractOptional, extractSingleton}
Expand Down Expand Up @@ -104,7 +104,7 @@ object Extractor {
* @return a Try[T].
*/
def extractMulti[T: MultiExtractor](nodeSeq: NodeSeq): Try[T] =
s"multi-extract: ${name[MultiExtractor[T]]} from ${renderNodes(nodeSeq)}" !?
s"extractMulti: ${name[MultiExtractor[T]]} from ${renderNodes(nodeSeq)}" !!
implicitly[MultiExtractor[T]].extract(nodeSeq)

/**
Expand Down Expand Up @@ -150,11 +150,14 @@ object Extractor {
* Method to extract child elements from a node.
* It is acceptable
*
* This method is deprecated because specifying member here is counter-productive.
*
* @param member the name of the element(s) to extract, according to the construct function (typically, this means the name of the member in a case class).
* @param node the node from which we want to extract.
* @tparam P the (MultiExtractor-able) underlying type of the result.
* @return a Try[P].
*/
@deprecated
def extractChildren[P: MultiExtractor](member: String)(node: Node): Try[P] = {
// TODO use Flog logging
val ts = translateMemberNames(member)
Expand Down Expand Up @@ -288,7 +291,6 @@ object Extractor {
*/
implicit val longExtractor: Extractor[Long] = stringExtractor map (_.toLong)


val logger: Logger = LoggerFactory.getLogger(Extractor.getClass)
}

Expand All @@ -312,9 +314,11 @@ trait MultiExtractor[T] extends NamedFunction[MultiExtractor[T]] {
* Trait which extends a function of type String => Extractor[T].
* When the apply method is invoked with a particular label, an appropriate Extractor[T] is returned.
*
* @tparam T the underlying type of the result of invoking apply.
* CONSIDER renaming this because it isn't an extractor, but a function which creates an extractor from a String.
*
* @tparam T the underlying type of the result of invoking apply. T may be an Iterable type.
*/
trait ElementExtractor[T] extends (String => Extractor[T]) {
trait TaggedExtractor[T] extends (String => Extractor[T]) {

/**
* Method to yield an Extractor[T], given a label.
Expand All @@ -324,3 +328,19 @@ trait ElementExtractor[T] extends (String => Extractor[T]) {
*/
def apply(label: String): Extractor[T]
}

trait SequenceExtractorByTag[T] extends TaggedExtractor[Seq[T]] {
val tags: Seq[String]

val pseudo: String

def valid(w: String): Boolean = w == pseudo

val tsm: MultiExtractor[Seq[T]]

def extract(node: Node): Try[Seq[T]] = sequence(for (tag <- tags) yield tsm.extract(node \ tag)) map (_.flatten)
}

class SubclassExtractor[T](val labels: Seq[String])(implicit tsm: MultiExtractor[Seq[T]]) extends Extractor[Seq[T]] {
def extract(node: Node): Try[Seq[T]] = sequence(for (label <- labels) yield tsm.extract(node \ label)) map (_.flatten)
}
Loading

0 comments on commit 7d889b5

Please sign in to comment.