Categories
RDF

Jena Week: Migrating the first example

Recovered from the Wayback Machine.

(Note: all examples are compiled and run on a Windows 2000 box, MySql 4.x, Java 1.4.1_01)

I downloaded and unzipped the Jena2 from the SourceForge project and first thing I noticed is that there is a lot of material with this download. With the classes for the ontology support as well as RDF, this is a large Java framework, providing support for all aspects of RDF and OWL, including an inferential engine, the ‘reasoner’.

The second thing I noticed is that the documentation for Jena2 is sketchy at best, with the tutorial still set for Jena 1.4, some migration guides, and the ubiquitous Javadocs. But hey! We all know that Java is self-documenting with Javadocs, so we don’t need to stinkin’ tutorials and user manuals. Besides, tutorials are for babies.

Seriously, the generated Java documentation, installation and migration guides, and the essential Jena Mini I/O are enough if you’ve worked with Jena previously. If not, hopefully the essays this week, migrating the Jena applications in the book to Jena2 will provide a good start in your efforts.

(If all goes well, next week we’ll work with the ontology classes and all of the other new Jena2 goodes. )

Once installed, I added all of the Jena jar files to my classpath, per the README document in the root directory. I then tested the installation using the test.bat file, but I could have used Ant, or used test.sh within a Unix environment. Once tested, second step was to start porting the first example Java application, reproduced here as a guide:

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem; import com.hp.hpl.mesa.rdf.jena.model.*; import com.hp.hpl.mesa.rdf.jena.common.PropertyImpl; import java.io.PrintWriter;

public class pracRDFFirst extends Object {

public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://www.burningbird.net/bbd/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = new ModelMem();

// create the resource Resource postcon = model.createResource(sURI);

// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);

// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

// Print RDF/XML of model to system output model.write(new PrintWriter(System.out));

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

This example is pretty simple: create an in-memory model, a new resource, and add two properties to that resource, both with the predicate “related”. Absolute URIs are used, and once the model is built, it’s printed out to the system. General exceptions are captured and the error message is printed. No other error checking and management is done.

The first step in migrating this example is to change the existing class structure to the new refactored one:

    * com.hp.hpl.mesa.rdf.jena.model -> com.hp.hpl.jena.rdf.model
    * com.hp.hpl.mesa.rdf.jena.vocabulary -> com.hp.hpl.jena.vocabulary

This is a bit tricky at first because not only is ‘mesa’ removed, the jena.rdf reference is reversed. Another change is the fact that there no longer is a specific ModelMem class or a specific PropertyImpl implementation class. This simplifies the number of Java classes that are included:

import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

The actual code of the application doesn’t change drastically. We’re using a class factor rather than new, but creating the resource and adding the properties doesn’t change:


import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

public class pracRDFFirst extends Object {
public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();
// create the resource Resource postcon = model.createResource(sURI);
// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);
// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

Once the model is built, to print it out with Jena, I used to use Jena’s Writer. In Jena2, this is replaced with InputStream and OutputStreams, a change significant enough for the Jena team to put out wht they call a “Rush Guide – Jena 1 Migration (Must Read)”.

According to the guide:

The Jena1 developer will note that all but one of these methods are new in Jena2. Jena1 mistakenly required the use of java.io.Reader and java.io.Writer. While these classes work well on a single machine, the way they address character encoding problems differs significantly from the solution offered by XML. A typical use of the Jena1 input interface such as mdl.read(new FileReader(fName)); is incorrect, and will give the wrong results if the file contains non-ASCII data. Also, in Jena1, mdl.write(new FileWriter(fName)); wrote incorrect XML for non-ASCII data (now fixed). However, these two bugs in Jena1 canceled each other out, as long as the system doing the reading had the same default character encoding as the one doing the writing, which is why it did not bite in a typical development environment. There is the substantial migration task when porting Jena1 code to Jena2 code of reviewing all the I/O calls and changing them to use InputStream’s and OutputStream’s.

Now, this is my kind of technical description, …which is why it did not bite in a typical development environment…. According to the guide, the old methods are still supported, and can still be useful and I found this so when I compiled the application without making the I/O change. However, Jena now traps for the bugs mentioned in the description and issues errors – errors that are almost guaranteed to occur.

You can still use Reader and Writer, but do so when you’re working with StringBuffer in memory, or when you specifically control the string encoding. Otherwise – go with the new OutputStream/InputStream objects. Only problem is, according to the Rush I/O guide example, to access the new OutputStream class, RDFWriter, use getRDFWriter. This was a typographical error, and to get RDFWriter, use getWriter on the model object, passing in an optional string with the serialization language. The default serialization language, RDF/XML, works so we don’t need to pass in the string.

The change to the code to use RDFWriter in the updated application is (outputting to System.out):

          
// Print RDF/XML of model to system output
          RDFWriter writer = model.getWriter();
          writer.write(model, System.out, null);

Easy enough to change. The complete new tiny application that creates an RDF model with one resource and a repeating property, printed out to system is:

import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

 

public class pracRDFFirst extends Object {

public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create the resource Resource postcon = model.createResource(sURI);

// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);

// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model, System.out, null);

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

Compiling the application and running it gives us the following serialized RDF/XML:

<rdf:RDF
    xmlns:j.0="http://burningbird.net/postcon/elements/1.0/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <j.0:related>http://burningbird.net/articles/monster3.htm</j.0:related>
    <j.0:related>http://burningbird.net/articles/monster2.htm</j.0:related>
  </rdf:Description>
</rdf:RDF>

That’s it, an application that compiles and runs within Jena2, and a remarkably pain free migration. Of course, this was a small application. Next essay in this series, we’ll start looking at slightly more complicated applications. I’m sure the headache factor of the migration will increase as the complications in the applications increase. Isn’t there a law saying this is so?

Categories
RDF

Jena Week: Lovely, lovely factories

Recovered from the Wayback Machine.

While factories in the real world tend to be messy, ugly things polluting the environment, within Java, they’re wonderful creations that hide much of the implementation detail of Java interfaces. This is particularly obvious when we take a look at porting the third example from Chapter 8 in Practical RDF to the new Jena2.

(No worries about skipping – at the end of the series I’ll post a file that contains all of the converted applications.)

The third example introduces the implementation of two concepts: one having to do with RDF and RDF/XML – bnodes, or blank nodes; the other having to do with hiding some of the implementation details when working with a pre-defined RDF vocabulary in Jena – RDF vocabulary classes.

The Java code from the book for the third example is:

 

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem; import com.hp.hpl.mesa.rdf.jena.model.*; import com.hp.hpl.mesa.rdf.jena.vocabulary.*; import com.burningbird.postcon.vocabulary.POSTCON; import java.io.FileOutputStream; import java.io.PrintWriter;

public class pracRDFThird extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sRelResource1 = “http://burningbird.net/articles/monsters2.htm”; String sRelResource2 = “http://burningbird.net/articles/monsters3.htm”;

try { // create an empty graph Model model = new ModelMem();

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.related, model.createResource(sRelResource1)) .addProperty(POSTCON.related, model.createResource(sRelResource2));

// create the bio bnode resource // and add properties Resource bio = model.createResource() .addProperty(DC.creator, model.createLiteral(“Shelley Powers”)) .addProperty(DC.publisher, model.createLiteral(“Burningbird”)) .addProperty(DC.title, model.createLiteral(“Tale of Two Monsters: Legends”, “en”));

// attach to main resource article.addProperty(POSTCON.bio, bio);

// Print RDF/XML of model to system output model.write(new PrintWriter(System.out));

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

This application code uses the cascade style of piggy backing instantiation of objects that are then passed to the function calls that instantiate other objects and so on. This is an effective technique to use if you’re not re-using interim objects.

Note also that the code creates a new resource that does not have a specific URI because it’s a blank node:

  Resource bio
     = model.createResource()

 

As you’ll remember from the book – you do have the book, now, don’t you? – a blank node is a resource where a URI is not meaningful, or doesn’t yet exist. In this example, the bio section doesn’t have a meaningful URI, yet. Once created, the bnode resource is then attached directly to the model’s top-level resource using the predicate, ‘bio’. Later we’ll see what the bnode looks like as generated RDF/XML.

One major change with this code from the previous example covered in the last post is that it uses another class, POSTCON, for the PostCon vocabulary elements. Though not a requirement, using a vocabulary has several advantages, including code reuse and modularization, as well as hiding some of the implementation characteristics. The Jena development team used this approach with several existing and widespread vocabularies, including DC, DCTERMS, and VCARD – all of which are included with the Jena installation.

The original code for the PostCon vocabulary class is:

package com.burningbird.postcon.vocabulary;

 

import com.hp.hpl.mesa.rdf.jena.common.ErrorHelper; import com.hp.hpl.mesa.rdf.jena.common.PropertyImpl; import com.hp.hpl.mesa.rdf.jena.common.ResourceImpl; import com.hp.hpl.mesa.rdf.jena.model.Model; import com.hp.hpl.mesa.rdf.jena.model.Property; import com.hp.hpl.mesa.rdf.jena.model.Resource; import com.hp.hpl.mesa.rdf.jena.model.RDFException;

public class POSTCON extends Object {

// URI for vocabulary elements protected static final String uri = “http://burningbird.net/postcon/elements/1.0/”;

// return URI for vocabulary elements public static String getURI() { return uri; }

// define the property labels and objects static final String nbio = “Bio”; public static Property bio = null; static final String nrelevancy = “Relevancy”; public static Property relevancy = null; static final String npresentation = “Presentation”; public static Resource presentation = null; static final String nhistory = “history”; public static Property history = null; static final String nmovementtype = “movementType”; public static Property movementtype = null; static final String nreason = “reason”; public static Property reason = null; static final String nstatus = “currentStatus”; public static Property status = null; static final String nrelated = “related”; public static Property related = null; static final String ntype = “type”; public static Property type = null; static final String nrequires = “requires”; public static Property requires = null;

// define the resources static final String nresource = “Resource”; public static Resource resource = null; static final String nmovement = “Movement”; public static Resource movement = null;

// instantiate the properties and the resource static { try {

// instantiate the properties bio = new PropertyImpl(uri, nbio); relevancy = new PropertyImpl(uri, nrelevancy); presentation = new PropertyImpl(uri, npresentation); history = new PropertyImpl(uri, nhistory); related = new PropertyImpl(uri, nrelated); type = new PropertyImpl(uri, ntype); requires = new PropertyImpl(uri, nrequires); movementtype = new PropertyImpl(uri, nmovementtype); reason = new PropertyImpl(uri, nreason); status = new PropertyImpl(uri, nstatus);

// instantiate the resources resource = new ResourceImpl(uri+nresource); movement = new ResourceImpl(uri+nmovement);

} catch (RDFException e) { ErrorHelper.logInternalError(“POSTCON”, 1, e); } } }

 

What a mess – all the implementation details for the interfaces are exposed, making for extra work and minimizing readability of the code. But all of that’s changed now in Jena2.

With Jena2, rather than using a series of …Impl classes, and having to implement the RDF class interfaces directly, the actual implementation of the interfaces occurs deep down inside the guts of Jena, through factory objects. This is where this type of implementation should occur so that we can focus on developing RDF applications, rather than on Java implementation language details.

Compare the POSTCON vocabulary class in Jena1 with the new one, defined using Jena2 functionality:

package com.burningbird.postcon.vocabulary;

 

import com.hp.hpl.jena.rdf.model.*;

public class POSTCON {

// URI for vocabulary elements protected static final String uri = “http://burningbird.net/postcon/elements/1.0/”;

// return URI for vocabulary elements public static String getURI() { return uri; }

private static Model model = ModelFactory.createDefaultModel();

// define the property labels and objects public static final Property bio = model.createProperty(uri + “bio”); public static final Property relevancy = model.createProperty(uri + “relevancy”); public static final Property presentation = model.createProperty(uri + “presentation”); public static final Property history = model.createProperty(uri + “history”); public static final Property movementtype = model.createProperty(uri + “movementType”); public static final Property reason = model.createProperty(uri + “reason”); public static final Property status = model.createProperty(uri + “status”); public static final Property related = model.createProperty(uri + “related”); public static final Property type = model.createProperty(uri + “type”); public static final Property requires = model.createProperty(uri + “requires”);

// define the resources public static final Resource Resource = model.createResource(uri + “Resource”); public static final Resource Movement = model.createResource(uri + “Movement”); }

 

The difference is significant, and greatly improved. Another approach to use could be to use the ResourceFactory object directly to create the individual items:

    public static final Property requires = ResourceFactory.createProperty(uri + “requires");
    public static final Resource Resource = ResourceFactory.createResource(uri + “Resource");

 

Looking through the source code for the vocabulary classes included with Jena, I see both approaches being used. Once the new POSTCON vocabulary class has been compiled, we can look at porting the rest of the third example from the book.

Returning to the code for the third example, the only changes that need to occur now to make this work with Jena2 is to use the ModelFactory to create the model, and update the code to use the new outputstream class, as discussed in the previous posting. The updated code now becomes:

import com.burningbird.postcon.vocabulary.POSTCON;

 

public class pracRDFThird extends Object{

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sRelResource1 = “http://burningbird.net/articles/monsters2.htm”; String sRelResource2 = “http://burningbird.net/articles/monsters3.htm”;

try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.related, model.createResource(sRelResource1)) .addProperty(POSTCON.related, model.createResource(sRelResource2));

// create the bio bnode resource // and add properties Resource bio = model.createResource() .addProperty(DC.creator, “Shelley Powers”) .addProperty(DC.publisher, “Burningbird”) .addProperty(DC.title, model.createLiteral(“Tale of Two Monsters: Legends”, “en”));

// attach to main resource article.addProperty(POSTCON.bio, bio);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model,System.out, null);

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

The resulting RDF/XML is:

<rdf:RDF
    xmlns:j.0="http://burningbird.net/postcon/elements/1.0/”
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#”
    xmlns:dc="http://purl.org/dc/elements/1.1/” >
  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <j.0:related rdf:resource="http://burningbird.net/articles/monsters2.htm"/>
    <j.0:related rdf:resource="http://burningbird.net/articles/monsters3.htm"/>
    <j.0:bio rdf:nodeID="A0″/>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A0″>
    <dc:creator>Shelley Powers</dc:creator>
    <dc:publisher>Burningbird</dc:publisher>
    <dc:title xml:lang="en">Tale of Two Monsters: Legends</dc:title>
  </rdf:Description>
</rdf:RDF>

 

The blank node is given a node identifier of “AO” to differentiate it in the model. Use caution with bnode identifiers – they lose all meaning outside of the particular instance of the model; they are not true URIs, but merely a placeholder and a convenience.

 

Well, that was fun. Still no hassle porting the code, and since we used a vocabulary class in the original application, we’ve helped minimize the code changes in all of the applications that use the class. Golly, isn’t it nice how this stuff works, sometimes?

Categories
RDF

Jena Week: Containers and namespaces

Recovered from the Wayback Machine.

The RDF/XML syntax differs a great deal from vanilla XML, not the least of which is there is no assumptions associated with the order of elements, and XML lacks many of the precision refinements built directly into RDF/XML.

For instance, in XML you can have several children of an element, but then you’d have to use DTDs or XML Schema to treat the children other than a group whereby order matters. In RDF/XML you can use containers and collections to provide additional information about the members.

Example five in the book created a specific type of Container, a Seq. The code for the example for Jena1 is as follows:

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem;
import com.hp.hpl.mesa.rdf.jena.model.*;
import com.hp.hpl.mesa.rdf.jena.vocabulary.*;
import com.burningbird.postcon.vocabulary.POSTCON;
import java.io.FileOutputStream;
import java.io.PrintWriter;

 

public class pracRDFFifth extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sHistory1 = “http://www.yasd.com/dynaearth/monsters1.htm”; String sHistory2 = “http://www.dynamicearth.com/articles/monsters1.htm”; String sHistory3 = “http://www.burningbird.net/articles/monsters1.htm”;

try { // create an empty graph Model model = new ModelMem();

// create Seq Seq hist = model.createSeq() .add (1, model.createResource(sHistory1) .addProperty(POSTCON.movementtype, model.createLiteral(“Add”)) .addProperty(POSTCON.reason, model.createLiteral(“New Article”)) .addProperty(DC.date, model.createLiteral(“1998-01-01T00:00:00-05:00″))) .add (2, model.createResource(sHistory2) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Moved to separate dynamicearth.com domain”)) .addProperty(DC.date, model.createLiteral(“1999-10-31:T00:00:00-05:00″))) .add (3, model.createResource(sHistory3) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Collapsed into Burningbird”)) .addProperty(DC.date, model.createLiteral(“2002-11-01:T00:00:00-5:00″)));

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.history, hist);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.setNsPrefix(“pstcn”, “http://burningbird.net/postcon/elements/1.0/”); writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

Note also that this code example introduces a method of changing the namespace abbreviation used, so that we don’t get the generic J0 we’ve been seeing in previous examples:

            // Print RDF/XML of model to system output
            RDFWriter writer = model.getWriter();
            writer.setNsPrefix("pstcn", “http://burningbird.net/postcon/elements/1.0/");
            writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

 

As with previous examples the primary changes are to the class library structure and to use the factory object to create the memory model. When compiling the application, though, errors appeared.

The setNSPrefix method on the Jena1 RDFWriter class has been removed. To set the namespace, we’ll need to use the code that Ian provided in my comments in the last example:

		// set namespace qualifier
		model.getGraph()
		.getPrefixMapping()
		.setNsPrefix( “pstcn",
		“http://burningbird.net/postcon/elements/1.0/” );

 

At this point no errors are occurring, and I get the generated RDF/XML shown in this file.

This RDF/XML is close, and valid, but not what I was expecting – the Jena code stripped the absolute URI for the primary resource down to a relative URI when attaching the Seq to the resource using a bnode:

  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <pstcn:history rdf:nodeID="A0″/>
  </rdf:Description>

 

Relative URIs are valid, they resolve to their parent document, or to whatever is specified with xml:base. Why Jena2 alters the URI to a relative one is a big mystery.

You can also set xml:base, but I haven’t been able to locate the class method to use to do this with Jena2. I’ll continue hunting this and hopefully post the information in the next essay

The complete code for this example is:

import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.*;
import com.burningbird.postcon.vocabulary.POSTCON;
import java.io.PrintWriter;

 

public class pracRDFFifth extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sHistory1 = “http://www.yasd.com/dynaearth/monsters1.htm”; String sHistory2 = “http://www.dynamicearth.com/articles/monsters1.htm”; String sHistory3 = “http://www.burningbird.net/articles/monsters1.htm”;

try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create Seq Seq hist = model.createSeq() .add (1, model.createResource(sHistory1) .addProperty(POSTCON.movementtype, model.createLiteral(“Add”)) .addProperty(POSTCON.reason, model.createLiteral(“New Article”)) .addProperty(DC.date, model.createLiteral(“1998-01-01T00:00:00-05:00″))) .add (2, model.createResource(sHistory2) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Moved to separate dynamicearth.com domain”)) .addProperty(DC.date, model.createLiteral(“1999-10-31:T00:00:00-05:00″))) .add (3, model.createResource(sHistory3) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Collapsed into Burningbird”)) .addProperty(DC.date, model.createLiteral(“2002-11-01:T00:00:00-5:00″)));

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.history, hist);

// set namespace qualifier model.getGraph() .getPrefixMapping() .setNsPrefix( “pstcn”, “http://burningbird.net/postcon/elements/1.0/” );

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

Well, this example’s conversion wasn’t without confusion. We’ve spent enough time on creating models – next example, we’ll look at reading a model in from an RDF/XML file, and accessing the individual statements.

Categories
Photography Weblogging Writing

Big Water

Recovered from the Wayback Machine.

Pretty tired today, and no, it has nothing to do with the peace party that happened in the comments to the last post. The participants worked things out for themselves, which is as it should be. I’m not sure what Happy Tutor is doing and where he’s taking it, but he’s a big boy and can handle burning material. Since he’s taken said burning material elsewhere, I am content.

I’m currently working on three articles for O’Reilly and some other promotional activity for the Practical RDF book. Additionally, I’ve been out virtually knocking on the doors of several local and national publications trying to re-awaken my moribund writing career. The end result of this activity is that I need to write. A lot. Knock a bit more, write a bit more, and repeat.

I also need to drop some of the bad writing habits I’ve picked up with weblog writing, such as the assumptions, the higher level of familiarity, the creative spelling and sentence construction, the use of ’so’, and the other quaint little short-cuts that fit this format, but not necessarily others.

So … I’m organizing my photos into online albums and am surprised at how many there are. Once finished, I need to select the best 50 for one portfolio, and then the best 20 of that number for another portfolio. However, when I think of my photos in something like a portfolio, my view of them changes and I become more critical of the work. It’s hard to explain but when you look at a photo one way, it can look good; but look at the photo from a different perspective – and I’m not talking the photo’s perspective – and it doesn’t quite work. At the rate I’m going, I’ll be lucky if I find five that work.

This phenomena happens with writing, too.

I’m planning a little trip South and along the Gulf in the nature of a combined vocational challenge/public interest jaunt. In September when the kiddies are in school, the weather cools, and the gas and motels are cheaper.

I don’t think I’ve posted the following photo previously. It’s the Chain of Rocks Bridge again, part of the old Route 66. I’m not saying the photo’s a portfolio member, but it’s cheerful, don’t you think? Imagine Nat King Cole singing in the background, and being in a convertible wearing a soft summer dress and iron maid bra, breeze blowing your hair in the warm, humid night. Get your kicks on Route 66.

rt66bridge.jpg

Categories
Writing

I am Alice or writing through the looking glass

Recovered from the Wayback Machine.

Sometimes enough disparate elements come together and you have to write about it because to do otherwise would be to toss fate’s good idea down the drain. So I find myself writing about writing and weblogging and self-censorship, when I think I should be writing about a girl and a bicycle and trees with eyes.

Last week I wrote about Fight or Flight, an essay about me coming to terms with how I deal with the negative comments that can occur with much of my writing – usually my technical writing, though I’ve attracted a few wasps with my political writing. I mentioned in the essay that I was inspired by another post but didn’t want to link to it because I didn’t want to bring relationships into a story, which ultimately was about my own journey for understanding. Unfortunately, the linkage occurred anyway, but fortunately, it didn’t leak into my writing – the words were accepted at face value, on their own worth, for good or bad.

There are times, though, such as now, when I’m not only inspired by others’ writing, I link to it because they’ve started a conversation and I’m only one voice in it. I am not so clever as to write with multiple voices in one writing; I can only write in my own.

Happy Tutor’s been writing quite a bit about the anger, aggressiveness, and the flaming that can creep into our conversations at times: here and here. In particular, one essay highlighted the conflict of differentiating between the flames of passion and the flames of cruelty and how, at times, the only difference between the two is one of perception. He writes:

Any time you talk about gender differences in a profession, you might as well expect a bashing. All I would ask, if you are seething with indignation, if your selfhood is now in play, is a) discharge yourself fully b) respect other people’s right to be wrong and c) recognize that we are all fearful and sometimes immobilized on this ground strewn with landmines. So, in other words, make allowances, if you can, for other people’s vulnerability, as you would hope they do for you – still, discharge the emotion fully. Any one with a good maternal instinct, or paternal, for that matter, is welcome to bind up the wounds we inflict on one another. The truth is just a word for what might emerge if we had the courage of our convictions, and the courage to learn by putting them at risk.

For a woman who writes from a platform of passion, I see these words as a benediction and a bane. If selfhood is engaged then we have to recourse but to expend our emotions, but does this mean we should not allow our selfhood to be engaged? Or does this mean, when we do, we have no option but to respond honestly, even passionately if passion is how our truth is conveyed?

I was considering this and not sure if I wanted to write about it when I received an email from Elaine about a posting she wrote in response to a Chris Locke diatribe, written in response to another weblogger’s posting. It would seem that the recipient of the Rageboy writing was so upset by it that she pulled not only the one posting, but her entire weblog.

Elaine writes Shame on you for shutting down a female blogger’s weblog:

So when bad boy Rage Boy spoilingly shuts down a fellow female’s blog for fun and fame, I say shame, shame on you, you sad, bad, boy blogger. Is that what blogging is about? Slash and burn? If you don’t like it kill it? (Sounds an awful lot like Dumbya, doesn’t it?)

I couldn’t read the original post that set Rageboy off, but I did see a piece of it at Blog Sisters. In it, the writer, Lindsay, talks about seeing a personal ad that read, in part, SWF, 40, attractive. Looking for man aged 40-55 for friendship, maybe more. Of the ad, and the need for relationships in general, she wrote:

t’s not so rare for me to talk to someone, who is about my age and has never had a relationship, and hear them saying “I feel so lonely. I wish someone wanted to be with me.” I even read in one person’s online journal that he wanted someone “to fill this hole inside of me.” The confusion of it all is so crazy, the thought that we need someone to fill the gaps in our lives, that we cannot live fully until we find our “soulmate” who is going to make us feel complete, and we can finally be happy and carefree and la la la.

I think most of this is due to laziness and insecurity. People don’t want to do the work on themselves so that they can feel complete independently. They want someone else to do it..

The problem is not that you haven’t found “the one.” The problem is that people are often too lazy to spend much time working on themselves alone, when they have the chance to do so, before they end up in a relationship and a situation where they will almost inevitably end up codependent.

There is much to agree with in Lindsay’s writing and I’ve written before that other people cannot make us whole, we can only do this ourselves. However, regardless of our wholeness or not, to see loneliness and react, at a minimum, without understanding and with intolerance is just as ‘ugly’ as to use words that overtly burn on their reading. It’s easy to condemn and criticize the woman in her 40’s who is lonely and seeking companionship, when one is not in that person’s shoes. Or, in Chris Locke’s shoes, worn loafers of a man in his 50’s, also lonely, always attracted to the flame that will ultimately burn him.

I, too, am lonely, without the closeness of a dear companion, a warm body to hold at night, a warm soul to hold during the day; I also am my 40’s and on the shady side of life, but where the lady in the ad sought companionship, I submerge my loneliness in my writing, and use it to give my writing depth. Does this make me superior? Or just different? Regardless, there’s pain in loneliness and to dismiss it with jejune assumptions of laziness is to invite response. Yes, even passionate response.

In Elaine’s comments, Lindsay wrote:

I didn’t actually choose to run. I had been thinking about shutting down my blog for awhile, because I’d been getting sick of all the nastiness going on in the blogosphere, especially on forums. Nothing like this had happened to me before though, and I figured it was the most opportune time to do what I’d already been planning on doing anyway.

I find it amusing how throughout this whole thing, there have been many comments about my age and implications about my lack of maturity and/or life experience, while at the same time the “adults” are the ones behaving in a way that is reminiscent of recess in Kindergarten. I’m sorry, but you’ll have to play without me.

I’m not defending Chris – as Lindsay wrote in Elaine’s comments, he also attacked her beliefs in addition to her writing, and I can’t defend that. But I can also understand his anger – easy for you to talk about laziness babe, when you’re not the one hurtin’.

The issue, though demonstrated effectively by this interchange, really has to do with that civility that Happy Tutor writes about. The problem with civility, though, is that it’s so open to interpretation. Some would say that being civil implies agreement, others that the discussion stay passionless and non-personal, and still others that anything goes as long as the parties agree to engage at a certain level.

It’s not easy to figure this all out. I think of reducing our writing in disagreement to assertions that begin with “I beg to differ”, and my blood runs cold; we have sold the heart of us, traded it in kind for polite political correctness. One person’s ugliness, is another’s beauty, and perhaps that’s what Tutor was saying – we must continue as we start because to do otherwise, is a lie.

In a technical post that was almost guaranteed to generate flames, I wrote about Pie/Echo/Atom and a recent seeming rejection of using RDF/XML for its primary format. How odd that a topic so seated in technology can be so potentially explosive, but any who know the players should, at this point, be shuddering at the implications. In this case, though there was disagreement and a combination of players that should have resulted in burning bits of cinder raining down on all – the conversation stayed civil. Not without bite, and not without passion, and there were hooks aplenty on which to launch flames, but it stayed civil.

I consider this thread a triumph for all the participants, but would others point to it and say, “See, lack of civility”?

This issue is only compounded because so many of us know each other, either through months, years of communication through our weblogs and phone calls and emails, or even in person.

Happy Tutor uncannily, or perhaps knowingly, also writes on self-censorship because of assocations we make with each other. This follows from Steve Himmer’s essay, where Steve talks about the impact knowing our audience has on us:

I’ve been thinking about an aspect of reading weblogs that I hadn’t considered before as I approached them as literature and whatnot. Namely, what difference does it make to our reading(s) when the blogger in question is an offline acquaintance, let alone someone we consider a friend.

So we lose the anonymity, and gain richer friendships, suggesting that we are forced (or feel forced) to censor ourselves more closely, be more careful about how we write ourselves and, perhaps more importantly, how we write about others…This suggests a dovetail between questions of audience and issues of acquaintance, but that makes sense: part of the shift from anonymity to known entity we undergo as webloggers as we become more and more social, on- and offline, corresponds to a shift our audience undergoes from nameless, faceless readers (or, when we begin writing, no readers) to known and named readers.

Tutor responds with:

In the course of this perceptive and congenial post, Steve suggests that as we become better known face to face, and via email, among our blogging circle, that we necessarily begin to censor ourselves, for fear of hurting those we now know, and for fear of the repercussions in the larger social world. Some might say that such self-censorship is a step towards civility. It can also be like “coming out,” an act of courage – or stupidity.

(Neither edge of Tutor’s sword is dull. I wonder if this is natural, or if he deliberately hones the safe side to keep his readers from experiencing comfort? )

Steve and Tutor both make a point: unlike other writing, the audience we have here is not that unknown Reader, but people we have come to know. Does this effect our writing? How can it not? But does this, then, lead to a lie – that unexpressed emotion that Tutor wrote about earlier?

Returning to my essay Fight or Flight, and my hesitancy to link to another weblog post. I did not link because I did not want to write to an audience of close friends – I wanted my audience to be Reader. I did not want to join a conversation, or invite a conversation, unless it had to do with the words, not past associations. This isolation is almost unheard of in weblogging, but it’s essential for writing. Writing centers around the words and the intent, the passion and that pesky truth – not friends’ expectations and feelings, old baggage and civility.

I hesitate now before I link to another weblogger’s writing. I think to myself, “Will this person want to be invited into this conversation?” and “Do I want this writing to become a conversation?” If I can’t unequivocally answer either of these questions with Yes, then I am not going to linclude a reference to their writing. Yet, this is considered uncivil. Do we choose writing, or do we choose community?

This would be all so much easier if we had thick skin and little sensitivity; but then we’d also be lacking in empathy and passion, joy as well as sorrow – pleasure and pain; what good the writing without the wonderful highs and lows?

I know one thing without ambiguity: I am a writer. Anything else, is and must be secondary; and the consequences of same is, all too often, more loneliness in which to feed the muse.

desertalone.jpg