Extracting CML from a Chem4Word authored document (C#)

January 21, 2010

My previous post was the first in a series demonstrating how CML embedded in DOCX files could be extracted (in that case using Java). For completeness I thought I ought to post some code to accomplish the same thing in C#. This should also allow people to get used to the packaging tools before we build up functionality in later posts.

If you would like a file containing CML to test this out with, one is available here.

Now for the code:


using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Chem4Word.Tools 
{
  public class OOXMLTools 
  {
    public ICollection GetCML(string path) 
    {
      ICollection list = new List();
      using (Package package = Package.Open(path, FileMode.Open)) 
      {
        foreach (PackagePart packagePart in package.GetParts()) 
        {
          if (packagePart.ContentType == "application/xml") 
          {
            using (StreamReader streamReader = 
               new StreamReader(packagePart.GetStream())) 
            {
              try 
              {
                XDocument xDocument = 
                  XDocument.Parse(streamReader.ReadToEnd());
                if (xDocument.XPathSelectElements(
              "//*[local-name()='cml' and namespace-uri()=
              'http://www.xml-cml.org/schema']").Count() > 0) 
                {
                  list.Add(xDocument);
                }
              }
              catch 
              {
                  // not valid XML so therefore can't be CML
              }
            }
          }
        }
      }
      return list;
    }
  }
}

So there we go. Pretty similar to the Java version really. Just in case you were wondering, I know I haven’t done a load of exception checking.


Extracting CML from a Chem4Word authored document (Java)

January 20, 2010

I have been meaning to write this post for ages and thanks to a recent tweet from Egon I’ve finally got round to it. Basically what I am going to do over a series of posts is explain how CML can be extracted from a DOCX (OOXML) file authored using Chem4Word. I’ll post methods in both Java and C# but I am starting off in Java.

A very quick into to DOCX and OOXML

There are plenty of blogs, papers, videos and the like out there which explain OOXML in various levels of detail. I don’t want to replicate that here but I think it will be useful to have a quick overview for reference. Microsoft developed the Open Packaging Convention (OPC) specification as a successor to its binary Microsoft Office file formats. The file-extension DOCX indicates an OPC document which should be edited using Microsoft Office Word 2007 (as opposed to the XSLX file extension for example which are OPC documents editable using Excel). A DOCX document is effectively a zip-file (the package) which contains the original text as a marked-up XML component (document.xml), with images and other embedded objects stored as separate files.

the simplified structure of an OPC document

The package-part word\document.xml contains the main text and body of the document. Chem4Word stores CML files in the customXml folder within the package. This directory contains pairs of files with names item[\d].xml and itemProps[\d].xml – itemProps[n] contains a list of all the namespaces and schemas used in item[n].

Getting the CML out – the brute force extraction method

The first method of extracting the CML files is the simplest. This method does not allow us to know anything more about the data other than it has been included somewhere in the document by the user. For example, we don’t know where and how it is being used in the document (or how many times). So, for the algorithm: iterate through all those files where the CML may be found, attempt to build each file as a XOM document, if it builds then search within it for a cml element from the cml namespace (see code below).

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import nu.xom.Builder;
import nu.xom.Document;

public class OOXMLTools {

  public static List<Document> GetCML(File file)
    throws ZipException, IOException  {

    ZipFile zipFile = new ZipFile(file);
    List<Document> list = new ArrayList<Document>();
    Builder builder = new Builder();
    Matcher m =
      Pattern.compile("customXml/item([1-9][0-9]*)\\.xml")
        .matcher("");

    for (Enumeration <? extends ZipEntry>
      entries = zipFile.entries(); entries.hasMoreElements();) {

      ZipEntry entry = entries.nextElement();
      if (m.reset(entry.getName()).matches()) {
        try {
          Document doc =
            builder.build(zipFile.getInputStream(entry));

          if (doc.query("//*[local-name()='cml' and
            namespace-uri()='http://www.xml-cml.org/schema']")
              .size() > 0) {

            list.add(doc);
          }

        } catch (Exception e) {
          // not an XML file so can't be CML
        }
      }
    }
    return list;
  }
}

If you would like to try it out here is a DOCX file with some chemistry in it. There are three chemistry zones in the document (containing testosterone [item1] and acetic acid [item3]) but only two CML files in the customXml directory because both testosterone instances point to the same backing CML file.

In following posts I will go further into how you can discover which representation is being used in the document, how many times a particular CML file is referenced and how the data is converted into the on screen representation.


First tentative steps in ClojureCLR

August 27, 2009

Jim and Nick (Day) have been using Clojure for a while on various projects and all too frequently I have heard exclamations of delight when they find what would have been 100s of lines of Java can be done in two or three of Clojure. I have spent most of the past year writing in C# and just haven’t been able to join in, although it has been good to have break from Java.

One of the things to come out of the Chem4Word project has been the idea of performing chemical changes via a stateless interface (CID – the Chemistry Interface Definition). This approach was strongly pushed by Savas and Jim (possibly as an excuse to learn yet another language). A stateless system lends itself beautifully to a functional language and as a bonus Clojure has both a CLR and JVM implementation so we can have a single definition which we can use on both platforms.

As a CompSci at Cambridge the first programming language you see is ML – probably because it makes it fairly easy to work out the big O. So I have some fond memories of functional programming (though quite what aroma it would require to really take me back does not bear thinking about) and (conveniently) a need for it.

The CLR implementation is still fairly bleeding edge and the installation process reminded me of the bad old days of Open Source software. Still 3 hours into the process and I had my REPL up and running and a function which would say Hello! not just to the world, but whoever happened to be passed to it. Tomorrow I shall be dusting off the ML part 1a handout by Larry Paulson (who broke off in lectures to teach us how to make bread the traditional way) and attempting any of the exercises I can find.

I’m looking forward to the Cambridge Clojure user group meeting and all this ML and functional talk means that a sneaky peak at F# over the long weekend is probably coming up too.


Dictionaries in CML

September 18, 2008

I am now allowed to be a bit more open about what I am up to following the public announcement of the chem4word project so I hope to be publishing more regularly about day-to-day (probably more like week-to-week) progress and thoughts.

I am currently preparing a set of exemplars and use cases for the first phase of the project. These provide a good source of example molecules and chemical concepts so that we (those with chemical background) can explain to them (everyone else) what on earth we are talking about. It is all too easy to forget that when we say something we know the implicit semantics but others may not. The preparation of this corpus has involved creating high-quality CML documents which conform to CMLLite (a subset of CML – effectively that required to represent chemistry in print).

CML uses dictionaries (via the dictRef attribute) liberally, this means that the schema can specify a single element which can be processed the same way each time but can hold different information. For example the property element can hold both a melting point and a molecular weight.

<cml version="3" convention="CMLLite"
xmlns="http://www.xml-cml.org/schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:cmlDict="http://www.xml-cml.org/dictionary/cml/"
xmlns:unitsDict="http://www.xml-cml.org/dictionary/units/">
<property dictRef="cmlDict:mw">
<scalar dataType="xs:double" units="unitsDict:dalton">247.3</scalar>
</property>
<property dictRef="cmlDict:mpt">
<scalar dataType="xs:double" units="unitsDict:c" min="202" max="205" />
</property>
</cml>

The document above should be familiar to anyone who has seen any CML before. However, there may be a difference. Each of the dictionary items (URIs in the dictRef) actually have definitions. I promised myself at the start of the project that I would never hand over any CML document which contained an undefined dictionary reference.

We will be making these dictionaries available, together with examples, during the project. I am also pushing for the dictionary items to be URLs for ease of use.

Oh! and I have also been learning C# and loving it…