private void appendLine(Document doc, Element parent, BxLine line, Object... hints) {
   Element node = doc.createElement("Line");
   appendPropertyIfNotNull(doc, node, "LineID", line.getId());
   appendBounds(doc, node, "LineCorners", line.getBounds(), hints);
   appendPropertyIfNotNull(doc, node, "LineNext", line.getNextId());
   appendProperty(doc, node, "LineNumChars", "");
   for (BxWord word : line.getWords()) {
     appendWord(doc, node, word, hints);
   }
   parent.appendChild(node);
 }
 @Override
 public double calculateFeatureValue(BxZone zone, BxPage page) {
   double charSpace = 0.0;
   for (BxLine line : zone.getLines()) {
     for (BxWord word : line.getWords()) {
       for (BxChunk chunk : word.getChunks()) {
         charSpace += chunk.getArea();
       }
     }
   }
   double ret = zone.getArea() - charSpace;
   if (ret < 0) {
     return 0.0;
   } else {
     return ret;
   }
 }