Efficient (and slightly tricky) overload of ++
on parameters which are
specifically of type com.codecommit.antixml.Group[_]
.
Efficient (and slightly tricky) overload of +:
on parameters which are
specifically of type com.codecommit.antixml.Node.
Efficient (and slightly tricky) overload of :+
on parameters which are
specifically of type com.codecommit.antixml.Node.
[use case]
[use case]
[use case]
Merges adjacent com.codecommit.antixml.Text as well as adjacent
com.codecommit.antixml.CDATA nodes to produce a Group
which represents
an identical XML fragment but with a minimized structure.
Merges adjacent com.codecommit.antixml.Text as well as adjacent
com.codecommit.antixml.CDATA nodes to produce a Group
which represents
an identical XML fragment but with a minimized structure. Slightly more
formally, for any XML fragment with n characters of textual data, there
are 2n possible ways of representing that fragment as a Group
. All
of these representations are semantically distinct (i.e. structurally different
in memory) but logically equivalent in that they will all generate the same
XML fragment if serialized. Of these 2n distinct representations,
there will be exactly one representation which is minimal, in that the
smallest possible number
of com.codecommit.antixml.Text and com.codecommit.antixml.CDATA nodes
are used to represent the textual data. This form may be considered
"canonical". This method converts an arbitrary Group
into its canonical
form, a logically equivalent Group
which represents the same XML fragment
in its structurally minimized form.
This method is perhaps best explained by an example:
val xml = Group(Text("Daniel "), Text("Spiewak")) xml.canonicalize // => Group(Text("Daniel Spiewak"))
The Group
resulting from the canonicalize
invocation will produce exactly
the same result as would xml
were we to invoke the toString
method on
each of them. However, the canonicalized result has only one text node for
the entire character block, while xml
(the original Group
) has two.
This is actually a very common gotcha in scala.xml
. The issue comes up
most frequently in the area of equality. As you can see in the example above,
xml
clearly will not be equivalent (according to the equals
method)
to xml.canonicalize
. However, it is very natural to assume that these
two structures are in fact equal due to their logical equivalence in
that they represent the same textual XML fragment. Oftentimes, people will
get around this issue in scala.xml
by converting all NodeSeq
(s) into
strings prior to comparison. In Anti-XML, all that is necessary to handle
potential semantic divergence in cases of logical equality is to simply
invoke the canonicalize
method on each of the two equality operands.
If true this group may contain an element with the given name as one of its children (recursively).
(Changed in version 2.9.0) The behavior of scanRight
has changed. The previous behavior can be reproduced with scanRight.reverse.
[use case]
Serializes the nodes in this Group
into their most compact XML representation
and concatenates the result.
Serializes the nodes in this Group
into their most compact XML representation
and concatenates the result. Note that the result of this method may not
be well-formed XML, since well-formed XML is required to have only a single
parent element (whereas a Group
may contain multiple nodes at its top level).
This is not a pretty-print. The resulting XML will not be formatted in any
way. It will be precisely the XML fragment represented by this Group
,
no more and no less.
The XML fragment represented by this Group
in String
form
Produces a scala.collection.immutable.Vector which contains all of the
nodes in this Group
.
Produces a scala.collection.immutable.Vector which contains all of the
nodes in this Group
. This function is guaranteed to run in constant time.
(Changed in version 2.9.0) transpose
throws an IllegalArgumentException
if collections are not uniformly sized.
Efficient (and slightly tricky) overload of updated
on parameters which are
specifically of type com.codecommit.antixml.Node.
Represents a collection of arbitrary nodes (com.codecommit.antixml.Node)). Note that this collection need not have a single root parent element. Thus, a valid
Group
could be as follows:This would correspond to the following XML fragment (note: not actually well-formed XML, since it is lacking a single root element):
Note that unlike
scala.xml
,Group
is not a special type of com.codecommit.antixml.Node! This design decision has a very profound impact on the framework as a whole. In general, the result is an API which is more consistent and more predictable than it otherwise would have been. However, it also resulted in some unfortunate sacrifices: specifically, full XPath semantics. The exact semantics of the\
and\\
operators are defined in their respective scaladocs.Group
is parameterized based on the type ofNode
it contains. In the general case (such as the one illustrated above), this will be exactlyNode
. However, there are some very common cases wherein aGroup
may have a more specific type than justNode
. For example:In this example,
results
will have typeGroup[Elem]
. This is because the selector employed ("name"
) can only produce results of typeElem
. This mechanism forms the basis for the typed selectors mechanism, which is extremely powerful and serves to eliminate a great deal of boiler-plate casting when traversing XML hierarchies.In the general case,
Group
is backed by an instance of scala.collection.immutable.Vector. This implementation detail is significant as it implies two things. First, the implementation ofGroup
is truly immutable, meaning that there are no tricky concurrency semantics to worry about. Second, unlikescala.xml
(which backs its sequences by eitherList
orArrayBuffer
, depending on phase of the moon), it is possible to perform efficient random-access and updates across the entireGroup
. Random access is implemented by theapply
method, while random "updates" are implemented by theupdated
method. Fast prepend and append operations are also available.Beyond this, all standard collection operations are available on
Group
(e.g.flatMap
,exists
,collect
,slice
, etc). The appropriate incantations have been spoken to allow these methods to return the correct type. Thus, if youmap
over aGroup
and your function returns something which extendsNode
, the result will be aGroup
. If your function returns something which does not extendNode
(e.g.Int
), then the result will be something else (probably a genericIndexedSeq
backed byVector
).Group
itself extends scala.collection.immutable.IndexedSeq and thus can be used in situations which require this abstraction.