
scales.xml.xpath.Functions.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scales-xml_2.11 Show documentation
Show all versions of scales-xml_2.11 Show documentation
An alternate Scala Xml processing library
The newest version!
package scales.xml.xpath
import scales.xml._
import impl.EqualsHelpers
import impl.IsFromParser
import dsl.DslBuilder
import scales.utils._
/**
* Type class representing Xml objects which provide qnames. Most of the
* functions allow for implicit scope to ease use in xpaths.
*/
trait Names[T] {
/**
* Returns the QName
*/
def name(implicit t : T) : Option[QName]
/**
* simplify the usage in Names
*/
protected[xml] def flatName(implicit t : T) : QName =
name(t).getOrElse(EmptyQName.empty)
}
// Note - 2.8.x doesn't allow multiple implicit lists so we must combine them and duplicate the interface
/**
* Dummy implicit filler for easing interface issues
*/
class DIF()
/**
* Represents an empty qname for those cases that should return empty string
*/
protected[xml] object EmptyQName {
/**
* Both namespace and localname are empty
*/
protected[xml] val empty = NoNamespaceQName("")(Xml10, IsFromParser)
}
/**
* Collects all type class based xpath functions, exposed via Functions in package
*
* Also adds aliases for the common functions
*/
trait Functions extends NameFunctions with TextFunctions {
/**
* hasLocalName for XmlPaths
*/
def hasLocalNameX( local : String ) : XmlPath => Boolean =
(x : XmlPath) => hasLocalName[XmlPath](local)(XmlPathNames)(x)
/**
* hasLocalName for AttributePaths
*/
def hasLocalNameA( local : String ) : AttributePath => Boolean =
(x : AttributePath) => hasLocalName[AttributePath](local)(AttributePathNames)(x)
}
/**
* Functions providing access to QNames
*/
trait NameFunctions {
private[NameFunctions] implicit def toQNameNF[T]( t : T )(implicit name : Names[T]) =
name.flatName(t)
/**
* Returns the localName
*/
def localName[T](implicit t : T, name : Names[T], d : DIF) : String =
t.local
/**
* Returns the localName
*/
def localName[T](t : T)(implicit name : Names[T]) : String =
localName(t, name, DIF.dif)
/**
* curried to allow direct drop in for predicates, if it is an item then it will return false
*/
def hasLocalName[T](localName : String)(implicit name : Names[T] ) : T => Boolean =
(t : T) => t.local == localName
/**
* Does the qname match exactly (prefix included if present)
*/
def isExactly[T](qname : QName)(implicit name : Names[T] ) : T => Boolean =
(t : T) => t ==== qname
/**
* Matches on prefix and namespace only
*/
def isEquivalent[T](qname : QName)(implicit name : Names[T] ) : T => Boolean =
(t : T) => t =:= qname
/**
* Returns the XPath QName - prefix:local or local
*/
def qname[T](implicit t : T, name : Names[T], d : DIF) : String =
t.qName
/**
* Returns the XPath QName - prefix:local or local
*/
def qname[T](t : T)(implicit name : Names[T]) : String =
qname(t, name, DIF.dif)
/**
* Returns the XPath QName - prefix:local or local
*/
def qName[T](implicit t : T, name : Names[T], d : DIF) : String =
qname(t, name, DIF.dif)
/**
* Returns the XPath QName - prefix:local or local
*/
def qName[T](t : T)(implicit name : Names[T]) : String =
qname(t, name, DIF.dif)
/**
* We cannot allow the QName to escape if its invalid.
*/
private[this] def testNonEmpty( r : QName ) =
if (r eq EmptyQName.empty)
error("A Names instance has returned the EmptyQName. This is not directly accessable")
else
r
/**
* Returns the QName, will throw if the QName is "empty"
*/
def name[T](implicit t : T, name : Names[T], d : DIF) : QName =
testNonEmpty(t)
/**
* Returns the QName, will throw if the QName is "empty"
*/
def name[T](t : T)(implicit iname : Names[T]) : QName =
name(t, iname, DIF.dif)
/**
* Will be true for all values of T except when the resulting QName is "empty".
*
* If hasQName is false then calling name will throw
*/
def hasQName[T](implicit t : T, name : Names[T], d : DIF) : Boolean =
name.name(t).isDefined
/**
* Will be true for all values of T except when the resulting QName is "empty".
*
* If hasQName is false then calling name will throw
*/
def hasQName[T](t : T)(implicit name : Names[T]) : Boolean =
hasQName(t, name, DIF.dif)
/**
* Returns the qualified name {namespace}local
*/
def qualifiedName[T](implicit t : T, name : Names[T], d : DIF) : String =
t.qualifiedName
/**
* Returns the qualified name {namespace}local
*/
def qualifiedName[T](t : T)(implicit name : Names[T]) : String =
qualifiedName(t, name, DIF.dif)
/**
* Returns either qualifiedName or prefix:{namespace}local when a prefix is present
*/
def pqName[T](implicit t : T, name : Names[T], d : DIF) : String =
t.pqName
/**
* Returns either qualifiedName or prefix:{namespace}local when a prefix is present
*/
def pqName[T](t : T)(implicit name : Names[T]) : String =
pqName(t, name, DIF.dif)
/**
* Returns the underlying namespace object
*/
def namespace[T](implicit t : T, name : Names[T], d : DIF) : UnderlyingNamespace =
t.namespace
/**
* matches only the namespace
*/
def hasNamespace[T](namespace : Namespace)(implicit name : Names[T]) : T => Boolean =
(t : T) => t.namespace == namespace
/**
* XPath namespace-uri function, returns the uri
*/
def namespaceUri[T](implicit t : T, name : Names[T], d : DIF) : String =
t.namespace.uri
/**
* XPath namespace-uri function, returns the uri
*/
def namespaceUri[T](t : T)(implicit name : Names[T]) : String =
t.namespace.uri
/**
* matches only the namespace
*/
def hasNamespace[T](namespaceUri : String)(implicit name : Names[T], d: DIF) : T => Boolean =
(t : T) => t.namespace.uri == namespaceUri
}
trait FunctionImplicits extends TextImplicits with NamesImplicits
object DIF {
// only used to seperate the interfaces, fully implicit gets this as well
val dif = new DIF()
}
/**
* Name type classes
*/
trait NamesImplicits {
// only used to seperate the interfaces, fully implicit gets this as well
implicit val dif = DIF.dif
implicit val attribNames = AttributeNames
implicit val attributePathNames = AttributePathNames
implicit val xpathNames = XmlPathNames
implicit val elemNames = ElemNames
implicit val xtreeNames = XmlTreeNames
implicit val qnameNames = QNameNames
implicit val aqnameNames = AQNameNames
implicit val dslNames = DslNames
implicit def attribPathsNames[T <: Iterable[XmlPath]] = AttributePathsNames.asInstanceOf[Names[AttributePaths[T]]]
implicit def xpathToNames[T <: Iterable[XmlPath]] = XPathNames.asInstanceOf[Names[XPath[T]]]
}
object AttributeNames extends Names[Attribute] {
def name(implicit t : Attribute) : Option[QName] = Some(EqualsHelpers.toQName(t.name))
}
object AttributePathsNames extends Names[AttributePaths[_]] {
def name(implicit a : AttributePaths[_]) = {
val r = a.attributes
r.headOption.map( x => EqualsHelpers.toQName( x.attribute.name ))
}
}
object AttributePathNames extends Names[AttributePath] {
def name(implicit t : AttributePath) : Option[QName] = Some(EqualsHelpers.toQName(t.attribute.name))
}
object ElemNames extends Names[Elem] {
def name(implicit t : Elem) : Option[QName] = Some(t.name)
}
object XmlTreeNames extends Names[XmlTree] {
def name(implicit t : XmlTree) : Option[QName] = Some(t.section.name)
}
object DslNames extends Names[DslBuilder] {
def name(implicit t : DslBuilder) : Option[QName] = Some(t.toTree.section.name)
}
object XmlPathNames extends Names[XmlPath] {
def name(implicit t : XmlPath) : Option[QName] = Some(t.tree.section.name)
}
object QNameNames extends Names[QName] {
def name(implicit t : QName) : Option[QName] = Some(t)
}
object AQNameNames extends Names[AttributeQName] {
def name(implicit t : AttributeQName) : Option[QName] = Some(EqualsHelpers.toQName(t))
}
object XPathNames extends Names[XPath[_]] {
def name(implicit a : XPath[_]) = {
val r = ScalesXml.fromXPathToIterable(a)
r.headOption.flatMap(_.focus(_ => None, t => XmlTreeNames.name(t)))
}
}
/**
* Type class for text values
*/
trait TextValue[T] {
/**
* The text value of a given object, .value for attributes & items, the accumalated text if its an elem
*/
def text(implicit t : T) : String
}
trait TextFunctions {
/**
* The text value of a given object, .value for attributes & items, the accumalated text if its an elem
*/
def text[T](implicit t : T, value : TextValue[T], d : DIF ) : String =
value.text
/**
* XPath name for text
*/
def string[T](implicit t : T, value : TextValue[T], d : DIF ) : String =
text(t, value, DIF.dif)
/**
* More readable version for XmlItems and Attributes, same as text
*/
def value[T](implicit t : T, value : TextValue[T], d : DIF ) : String =
text(t, value, DIF.dif)
/**
* XPath normalize-space function, replaces all consecutive whitespace with " " and trims.
*/
def normalizeSpace[T](implicit t : T, value : TextValue[T], d : DIF ) : String =
normalizeSpaceS(value.text)
/**
* The text value of a given object, .value for attributes & items, the accumalated text if its an elem
*/
def text[T](t : T)(implicit value : TextValue[T]) : String =
text(t, value, DIF.dif)
/**
* XPath name for text
*/
def string[T](t : T)(implicit value : TextValue[T]) : String =
text(t, value, DIF.dif)
/**
* More readable version for XmlItems and Attributes, same as text
*/
def value[T](t : T)(implicit value : TextValue[T] ) : String =
text(t, value, DIF.dif)
/**
* XPath normalize-space function, replaces all consecutive whitespace with " " and trims.
*/
def normalizeSpace[T](t : T)(implicit value : TextValue[T] ) : String =
normalizeSpaceS(value.text(t))
}
trait TextImplicits {
implicit val xtreeText = XmlTreeText
implicit val attribText = AttributeText
implicit val attribPathText = AttributePathText
implicit val xmlpathText = XmlPathText
implicit val itemText = XmlItemText
implicit val itemOrElemText = ItemOrElemText
implicit val dslText = DslText
implicit def attribPathsText[T <: Iterable[XmlPath]] = AttributePathsText.asInstanceOf[TextValue[AttributePaths[T]]]
implicit def xpathToTextValue[T <: Iterable[XmlPath]] = XPathText.asInstanceOf[TextValue[XPath[T]]]
}
object XmlTreeText extends TextValue[XmlTree] {
def text(implicit t: XmlTree): String = {
t.fold(new StringBuilder())
{ (walker, sb) =>
if (walker.isLeft) {
walker.left.get match {
case Text(text) => sb.append(text)
case CData(text) => sb.append(text)
case _ => ()
}
}
sb
}.toString
}
}
object DslText extends TextValue[DslBuilder] {
def text(implicit t : DslBuilder) = XmlTreeText.text(t.toTree)
}
object XmlPathText extends TextValue[XmlPath] {
def text(implicit t : XmlPath) =
t.focus(_.value, XmlTreeText.text(_))
}
object ItemOrElemText extends TextValue[ItemOrElem] {
def text(implicit t : ItemOrElem) =
t.fold(_.value, XmlTreeText.text(_))
}
object AttributeText extends TextValue[Attribute] {
def text(implicit a : Attribute) = a.value
}
object AttributePathText extends TextValue[AttributePath] {
def text(implicit a : AttributePath) = a.attribute.value
}
object AttributePathsText extends TextValue[AttributePaths[_]] {
def text(implicit a : AttributePaths[_]) =
if (a.attributes.size == 0) ""
else a.attributes.head.attribute.value
}
object XmlItemText extends TextValue[XmlItem] {
def text(implicit a : XmlItem) = a.value
}
object XPathText extends TextValue[XPath[_]] {
def text(implicit a : XPath[_]) = {
val r = ScalesXml.fromXPathToIterable(a)
if (r.size == 0) ""
else XmlPathText.text( r.head )
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy