Skip to content
This repository has been archived by the owner on May 15, 2019. It is now read-only.

Fixed some bugs which I introduced with the last pull request. #89

Closed
wants to merge 11 commits into from
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -8,6 +8,7 @@ project/plugins/src_managed/
*.iml
*.ipr
*.iws
*.*~
.idea
.ensime
.DS_Store
Expand Down
25 changes: 10 additions & 15 deletions README.rst
Expand Up @@ -34,16 +34,16 @@ We are exploring `many ideas`_ for this project. It will be
interesting to see where things go!

.. _ADTs: http://en.wikipedia.org/wiki/Algebraic_data_type
.. _many ideas: http://dl.dropbox.com/u/1679797/anti-xml-todo.html
.. _many ideas: https://github.com/djspiewak/anti-xml/issues
.. _Novell Vibe: http://vibe.novell.com


Usage
=====

The Maven artifact descriptor for the latest *stable* version of
Anti-XML is as follows: ``com.codecommit:anti-xml_2.9.1:0.3``. We also regularly
push ``-SNAPSHOT`` releases to the Scala-Tools_ "snapshots" repository, for all
Anti-XML is as follows: ``net.hamnaberg:anti-xml_2.9.1:0.3``. We also regularly
push ``-SNAPSHOT`` releases to the Sonatype_ "snapshots" repository, for all
five of you who like to live dangerously. You should be able to use this
descriptor to easily add Anti-XML as a dependency to any project with a
Maven-compatible build system (Maven, Buildr, SBT, Gradle, Ivy, etc). The stable
Expand All @@ -53,18 +53,18 @@ build systems.

**SBT**::

val antiXML = "com.codecommit" %% "anti-xml" % "0.3"
val antiXML = "net.hamnaberg" %% "anti-xml" % "0.5"

**Buildr**::

compile.with "com.codecommit:anti-xml_#{Scala.version}:jar:0.3"
compile.with "net.hamnaberg:anti-xml_#{Scala.version}:jar:0.5"

**Maven2**::

<dependency>
<groupId>com.codecommit</groupId>
<groupId>net.hamnaberg</groupId>
<artifactId>anti-xml_2.9.1</artifactId>
<version>0.3</version>
<version>0.5</version>
</dependency>


Expand All @@ -73,17 +73,12 @@ Supported Versions of Scala

Anti-XML is cross-built_ for the following Scala versions:

* **2.9.2**
* **2.9.1**
* **2.9.0-1**
* **2.9.0**

Support for the 2.8.x stream is being dropped in version 0.3. It is believed
that 2.9.x has had sufficient time to mature and there is very little reason to
continue to work with 2.8.1. However, if there is demand for a 2.8.1 (or 2.8.0)
compatible release, open an issue and I will manually build a JAR for the appropriate
version.

.. _cross-built: http://code.google.com/p/simple-build-tool/wiki/CrossBuild
.. _cross-built: http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build.html
.. _Specs2: http://etorreborre.github.com/specs2/
.. _ScalaCheck: http://code.google.com/p/scalacheck/

Expand All @@ -106,5 +101,5 @@ worry, curly braces aren't a religious issue here) and explains the legal
mumbo-jumbo involved in contributing.

.. _issue tracker:
.. _official TODO list: http://dl.dropbox.com/u/1679797/anti-xml-todo.html
.. _official TODO list: https://github.com/djspiewak/anti-xml/issues
.. _CONTRIBUTING.rst: anti-xml/tree/master/CONTRIBUTING.rst
51 changes: 41 additions & 10 deletions build.sbt
@@ -1,10 +1,10 @@
name := "anti-xml"

organization := "com.codecommit"
organization := "no.arktekk"

version := "0.4-SNAPSHOT"

crossScalaVersions := Seq("2.9.1", "2.9.0-1", "2.9.0")
crossScalaVersions := Seq("2.9.2", "2.9.1", "2.9.0-1", "2.9.0")

scalaVersion := "2.9.1"

Expand Down Expand Up @@ -45,11 +45,11 @@ InputKey[Option[String]]("test-perf") <<= inputTask { (args: TaskKey[Seq[String]

doc in Compile <<= (clean in Compile, doc in Compile) map { (c, d) => d }

scaladocOptions in Compile <++= (unmanagedSourceDirectories in Compile) map { (usd) =>
scalacOptions in Compile in doc <++= (unmanagedSourceDirectories in Compile) map { (usd) =>
val scalaSrc: File = (usd filter { _.toString endsWith "scala" }).head
Seq(
"-sourcepath", scalaSrc.toString,
"-doc-source-url", "https://github.com/djspiewak/anti-xml/tree/master/src/main/scala€{FILE_PATH}.scala"
"-doc-source-url", "https://github.com/arktekk/anti-xml/tree/master/src/main/scala€{FILE_PATH}.scala"
)
}

Expand All @@ -65,13 +65,44 @@ publishArtifact in (Compile, packageSrc) := true

publishArtifact in (Test, packageSrc) := false

publishTo <<= version { (v: String) =>
val nexus = "http://nexus.scala-tools.org/content/repositories/"
if(v endsWith "-SNAPSHOT") Some("Scala Tools Nexus" at nexus + "snapshots/")
else Some("Scala Tools Nexus" at nexus + "releases/")
publishTo <<= (version) apply { (v: String) =>
if (v.trim().endsWith("SNAPSHOT")) {
Some("Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots")
} else {
Some("Sonatype Nexus Staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2")
}
}

credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")

resolvers += ScalaToolsSnapshots

//Maven central stuff
homepage := Some(new URL("http://anti-xml.org"))

startYear := Some(2011)

licenses := Seq(("BSD", new URL("https://github.com/arktekk/anti-xml/blob/master/LICENSE.rst")))

pomExtra <<= (pomExtra, name, description) {(pom, name, desc) => pom ++ xml.Group(
<scm>
<url>http://github.com/arktekk/anti-xml</url>
<connection>scm:git:git://github.com/arktekk/anti-xml.git</connection>
<developerConnection>scm:git:git@github.com:arktekk/anti-xml.git</developerConnection>
</scm>
<developers>
<developer>
<id>djspiewak</id>
<name>Daniel Spiewak</name>
<url>http://twitter.com/djspiewak</url>
</developer>
</developers>
<contributors>
<contributor>
<name>Erlend Hamnaberg</name>
<url>http://twitter.com/hamnis</url>
</contributor>
<contributor>
<name>Trygve Laugstøl</name>
<url>http://twitter.com/trygvis</url>
</contributor>
</contributors>
)}
2 changes: 1 addition & 1 deletion project/build.properties
@@ -1 +1 @@
sbt.version=0.11.0
sbt.version=0.12.1
7 changes: 5 additions & 2 deletions project/plugins.sbt
@@ -1,3 +1,6 @@
resolvers += "Scala-Tools Maven2 Snapshots Repository" at "http://scala-tools.org/repo-snapshots"
addSbtPlugin("org.ensime" % "ensime-sbt-cmd" % "0.1.0")

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.1.0")

addSbtPlugin("no.arktekk.sbt" % "aether-deploy" % "0.6")

addSbtPlugin("org.ensime" % "ensime-sbt-cmd" % "0.0.7")
35 changes: 15 additions & 20 deletions src/main/scala/com/codecommit/antixml/node.scala
Expand Up @@ -28,8 +28,6 @@

package com.codecommit.antixml

import java.io.Writer

/**
* Root of the `Node` ADT, representing the different types of supported XML
* nodes which may appear in an XML fragment. The ADT itself has the following
Expand Down Expand Up @@ -182,13 +180,13 @@ case class Elem(prefix: Option[String], name: String, attrs: Attributes, scope:
/**
* Convenience method to allow adding children in a chaining fashion.
*/
def addChildren(children: Group[Node]) = copy(children = children ++ children)
def addChildren(newChildren: Group[Node]) = copy(children = children ++ newChildren)

/**
* Convenience method to allow replacing all children in a chaining fashion.
*/
def withChildren(children: Group[Node]) = copy(children = children)

/**
* Adds a namespace with a given prefix
*/
Expand All @@ -211,14 +209,17 @@ case class Elem(prefix: Option[String], name: String, attrs: Attributes, scope:
}
"ns" + i
}
var currentNS = scope

//could be implemented using a fold
namespaces.foreach{
case (x, y) if (currentNS.find{case (_, z) => z == y}.isDefined) => //namespace is already registered. do nothing.
case ("", y) => currentNS = currentNS + (nextValidPrefix -> y)
case (x, y) => currentNS = currentNS + (x -> y)
def mapit(namespaces: Map[String, String], tuple: (String, String)) = tuple match {
case (x, y) if (namespaces.find{case (_, z) => z == y}.isDefined) => namespaces
case ("", y) if (namespaces.get("").isEmpty) => namespaces + ("" -> y) //if the empty namespace has not been defined already
case ("", y) => {
val p = nextValidPrefix
namespaces + (p -> y)
}
case (x, y) => namespaces + (x -> y)
}

val currentNS = namespaces.foldLeft(scope){case (ns, tuple) => mapit(ns, tuple)}
if (currentNS == scope) this else copy(scope = currentNS)
}
}
Expand Down Expand Up @@ -255,9 +256,7 @@ object Elem extends ((Option[String], String, Attributes, Map[String, String], G
* does ''not'' escape characters on output, use [[com.codecommit.antixml.CDATA]].
*/
case class Text(text: String) extends Node {
import Node.hasOnlyValidChars

if (!hasOnlyValidChars(text))
if (!Node.hasOnlyValidChars(text))
throw new IllegalArgumentException("Illegal character in text '" + text + "'")

override def toString = Node.escapeText(text)
Expand All @@ -282,12 +281,10 @@ case class Text(text: String) extends Node {
* performs escaping, use [[com.codecommit.antixml.Text]]
*/
case class CDATA(text: String) extends Node {
import Node.hasOnlyValidChars

if (text.contains("]]>"))
throw new IllegalArgumentException("CDATA nodes can't contain ']]>'")

if (!hasOnlyValidChars(text))
if (!Node.hasOnlyValidChars(text))
throw new IllegalArgumentException("Illegal character in CDATA '" + text + "'")

override def toString = "<![CDATA[" + text + "]]>"
Expand All @@ -307,9 +304,7 @@ case class CDATA(text: String) extends Node {
* }}}
*/
case class EntityRef(entity: String) extends Node {
import Node.hasOnlyValidChars

if (!hasOnlyValidChars(entity))
if (!Node.hasOnlyValidChars(entity))
throw new IllegalArgumentException("Illegal character in EntityRef '" + entity + "'")

override def toString = "&" + entity + ";"
Expand Down
38 changes: 38 additions & 0 deletions src/test/resources/lots-of-text.txt
@@ -0,0 +1,38 @@
Fetched from http://www.cpan.org/modules/by-module/XML/CHANG-LIU/XML-Node-0.10.readme

Here is a quick but complete example to show you how XML::Node promises
to keep your XML processing scripts short and clear.
---------- orders.xml ----------------------------------------------
<Orders>
<Order ID="0008">
<Item>A Book</Item>
<Quantity>1</Quantity>
<TagsThatIDontCare>Something</TagsThatIDontCare>
</Order>
<TagsThatIDontCare>Blah Blah</TagsThatIDontCare>
</Orders>

---------- parse-orders.pl ------------------------------------------
use XML::Node;

my $item = "";
my $quantity = "";
my $id = "";

$p = XML::Node->new();

$p->register(">Orders>Order:ID","char" => \$item);
$p->register(">Orders>Order>Item","char" => \$item);
$p->register(">Orders>Order>Quantity","char" => \$quantity);
$p->register(">Orders>Order","end" => \&handle_order_end);

print "Processing file [orders.xml]...\n";
$p->parsefile("orders.xml");

sub handle_order_end
{
print "Found order [$id] -- Item: [$item] Quantity: [$quantity]\n";
$id="";
$item = "";
$quantity = "";
}
34 changes: 34 additions & 0 deletions src/test/scala/com/codecommit/antixml/NodeSpecs.scala
Expand Up @@ -103,6 +103,30 @@ class NodeSpecs extends Specification with DataTables with ScalaCheck with XMLGe
}
}

"add children conveniently" in {
val elem = Elem(None, "foo", Attributes(), Map(), Group())
val withChildren = elem.addChildren(Group(Elem(None, "bar", Attributes(), Map(), Group()), Text("Hello")))
withChildren.children.size must beEqualTo(2)
}

"replace children conveniently" in {
val elem = Elem(None, "foo", Attributes(), Map(), Group(Text("Somewhat crazy")))
val withChildren = elem.withChildren(Group.empty)
withChildren.children must beEmpty
}

"add namespace conveniently" in {
val elem = Elem(None, "foo", Attributes(), Map("" -> "urn:foo:bar"), Group(Text("Somewhat crazy")))
val withChildren = elem.addNamespace("bar", "urn:foo:baz")
withChildren.scope must beEqualTo(Map("" -> "urn:foo:bar", "bar" -> "urn:foo:baz"))
}

"generate namespace" in {
val elem = Elem(None, "foo", Attributes(), Map("" -> "urn:foo:bar"), Group(Text("Somewhat crazy")))
val withChildren = elem.addNamespace("", "urn:foo:baz")
withChildren.scope must beEqualTo(Map("" -> "urn:foo:bar", "ns1" -> "urn:foo:baz"))
}

"detect illegal attribute prefixes" in check { str: String =>
name unapplySeq str match {
case Some(_) => Elem(None, "foo", Attributes(QName(Some(str), "bar") -> "bar"), Map(), Group()) must not(throwAn[IllegalArgumentException])
Expand Down Expand Up @@ -148,6 +172,11 @@ class NodeSpecs extends Specification with DataTables with ScalaCheck with XMLGe
"escape reserved characters when serialized" in {
Text("Lorem \" ipsum & dolor ' sit < amet > blargh").toString mustEqual "Lorem \" ipsum &amp; dolor ' sit &lt; amet &gt; blargh"
}
"Support large texts without overflowing" in {
val text = io.Source.fromInputStream(getClass.getResourceAsStream("/lots-of-text.txt")).getLines().mkString("\n")
Text(text).toString mustEqual Node.escapeText(text)
}

}

"cdata nodes" should {
Expand All @@ -157,5 +186,10 @@ class NodeSpecs extends Specification with DataTables with ScalaCheck with XMLGe
"Reject the ]]> string in the constructor" in {
CDATA("la di ]]> da") must throwAn[IllegalArgumentException]
}
"Support large texts without overflowing" in {
val text = io.Source.fromInputStream(getClass.getResourceAsStream("/lots-of-text.txt")).getLines().mkString("\n")
CDATA(text).toString mustEqual "<![CDATA[%s]]>".format(text)
}

}
}