OpenOffice.org ODF, Python and XML
OpenOffice.org Writer showed what we expected. Both the double hyphen and the en dash changed into em dashes, and the starting double quote curves the right way.
Now, here's the rest. The expression to deal with the ending double quote is the mirror image of the starting double quote. In order to write an ending/closing double quote, we require the quote character either to be at the end of the string (\Z) or followed by whitespace. Again, when we do the replacement, we want to replace only the quote itself, not the whitespace. Hence, the Ending Double-quote PATtern (eDpat) is given by:
eDpat = re.compile(r'("\Z)|("(?=\s))', re.U)By the way, we compile all these patterns because we're going to use them over and over again when processing documents.
To handle single quotes ('like these'), we basically can do the same thing, except for a couple of issues. First, is the problem of contractions. When handling a double-quote character, we didn't cover the case where it was surrounded on both sides by non-whitespace. With single quotes (or apostrophes), we can't avoid that, because of words such as can't. Therefore, although the starting single-quote pattern can match the starting double-quote pattern, the other one, which doubles as an apostrophe in contractions, has a looser pattern. Here's what I came up with:
eSpat = re.compile(r"(?<=\S)'", re.U)
Because the pattern has an apostrophe in it, we delimit the pattern string using double-quote characters. This expression matches a single quote, but only when preceded immediately by a non-whitespace character.
The second issue, which the code doesn't address, is that of contractions beginning with an apostrophe, such as 'tis the season or stick 'em up.
The script treats the leading apostrophe like the start of a single-quoted phrase, and the single quote will face the wrong way. This probably will need a manual work-around.
Putting all this together, we have fix4.py:
#!/usr/bin/python -tt
import xml.dom.minidom
import sys
import re # new in fix3.py
DEBUG = 1
def dprint(what):
if DEBUG == 0: return
sys.stderr.write(what.encode('ascii',
'replace') + '\n')
emDash=u'\u2014'
enDash=u'\u2013' # new in fix3.py
sDquote=u'\u201c' # new in fix3.py
eDquote=u'\u201d' # new in fix4.py
sSquote=u'\u2018' # new in fix4.py
eSquote=u'\u2019' # new in fix4.py
# sDpat: pattern for starting dbl quote, as
# "Go! <-- the quote there
# We look for it either at start (\A) or
# after a space (\s), and we want it to be
# followed by a non-space
sDpat = re.compile(r'(\A|(?<=\s))"(?=\S)', re.U) # new in fix3.py
eDpat = re.compile(r'("\Z)|("(?=\s))', re.U) # new in fix4.py
sSpat = re.compile(r"(\A|(?<=\s))'(?=\S)", re.U) # new in fix4.py
eSpat = re.compile(r"(?<=\S)'", re.U) # new in fix4.py
def fixdata(td, depth):
dprint("depth=%d: childNode: %s" %
(depth, td.data))
# OK, so '--' becomes em dash everywhere
td.data = td.data.replace('--', emDash)
# Change 'en' dash to 'em' dash
td.data = td.data.replace(enDash , emDash) # new in fix3.py
# Make a nice starting curly-quote # new in fix3.py
td.data = sDpat.sub(sDquote, td.data) # new in fix3.py
td.data = eDpat.sub(eDquote, td.data) # new in fix4.py
# Make nice curly single-quote characters
td.data = sSpat.sub(sSquote, td.data) # new in fix4.py
td.data = eSpat.sub(eSquote, td.data) # new in fix4.py
def handle_xml_tree(aNode, depth):
if aNode.hasChildNodes():
for kid in aNode.childNodes:
handle_xml_tree(kid, depth+1)
else:
if 'data' in dir(aNode):
fixdata(aNode, depth)
def doit(argv):
doc = xml.dom.minidom.parse(argv[1])
handle_xml_tree(doc, 0)
sys.stdout.write(doc.toxml('utf-8'))
if __name__ == "__main__":
doit(sys.argv)
Let's try that on our example:
% ln -sf fix4.py fixit.py % ./fixit.sh ex3.odt ex3-4.odt depth=5: childNode: The ?en? dash ? is too short depth=5: childNode: The ?em? dash ? which is longer ? is what we need. depth=5: childNode: And two hyphens -- ugly -- should be turned into ?em? dashes. depth=5: childNode: This line has "straight double quotes" depth=5: childNode: These 'single quotes' aren't pretty. % oowriter ex3-4.odt
Let's review what we've done here:
Wrote scripts to unpack and repack ODF files.
Learned about using Python to understand the structure of ODF files.
Wrote a Python program to perform useful transformations on an OpenOffice.org Writer file, using regular expressions and the built-in string methods.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- RSS Feeds
- Trying to Tame the Tablet
- New Products
- What's the tweeting protocol?
- Dart: a New Web Programming Experience
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.





2 hours 16 min ago
4 hours 49 min ago
9 hours 28 min ago
11 hours 50 min ago
1 day 4 hours ago
1 day 7 hours ago
1 day 8 hours ago
1 day 9 hours ago
1 day 9 hours ago
1 day 14 hours ago