Skip to content

Instantly share code, notes, and snippets.

@mkaatman
Forked from wbrisett/add_navtitles.rb
Last active December 15, 2015 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkaatman/5212445 to your computer and use it in GitHub Desktop.
Save mkaatman/5212445 to your computer and use it in GitHub Desktop.
Update to Wayne's script. Adds XML indentation on maps.
Script: add_navtitle.rb
Required: Ruby
http://rubyinstaller.org/downloads/ (for Windows)
http://www.ruby-lang.org/en/downloads/ (for Linux, Mac OS X, etc.)
Ubuntu 12.10 Install line:
sudo apt-get install ruby1.9.1 libruby1.9.1 ruby-libxml ruby1.9.1-dev
sudo apt-get install libxml2 libxml2-dev libxslt1.1 libxslt1-dev libreadline-dev
gem install nokogiri
Note: Ruby is already installed on \\pavas01.lsi.com
About this Script:
With the testing of trying to move DITA structured topics to local computers, using the extract map instead of extracting individual topics is more enticing. However, when you extract a map and open it in FrameMaker, unless you have manually added the navtitle attribute to each item in a map, then you will only see the v1234.xml names. When a navtitle is added to each item in a map, you see that title instead of the filename. You can individually add navtitle to each topic in the map via Vasont, but I find that a bit tedious.
This script will read the current working directory (where you are) and read in each map, make a backup copy of the map, open each topic listed in the map, pull in the title from each topic, then rewrite each map with the navtitle.
That rewritten map has to be loaded back into Vasont using the primary load method.
Syntax:
ruby add_navtitle.rb <-- Processes all maps in the current directory you are in.
or
ruby add_navtitle.rb <directory>
A directory called ditamap_backup is created in the directory where the maps are located. This is done in case something goes wrong with the script. The original untouched ditamaps are available in that directory. If you do not need the maps after the add_navtitle script has completed, you can delete the folder.
Change History:
===============
(versioning information is available within the script itself. You need to open the script in a text editor to read the versioning information).
2.0 December 2012- Complete rewrite of script.
2.1 March 2012 - Changed the way files are read in and created a backup of the map in case it is needed.
# Version 3.0 March 2013
# Changed reading of files from binary back to text.
# Added backup folder "...just in case"
# Added fix for Vasont extract Maps
# Added .dita files to script
# Changed parsing of title to xpath via Nokogiri
require 'fileutils'
require 'nokogiri'
def removeattributes (xml)
search_line = xml
if search_line.match(/\dxml\s/) then
search_line.gsub!(/xml\s/, "xml")
elsif search_line.match(/\ddita\s/) then
search_line.gsub!(/dita\s/, "dita")
end
if search_line.match(/product=/) # if product is in line, have to remove it
search_line.gsub!(/.product.*/, "")
if search_line.match(/(xml\"|dita\")/) then
search_line.gsub!(/\"/, "")
end
end
if search_line.match (/\">/) then
search_line.gsub!(/\">/, "")
elsif search_line.match (/\">./) then
search_line.gsub!(/\">./, "")
elsif search_line.match (/>/) then
search_line.gsub!(/>/, "")
end
return search_line
end
def cleanup(xml)
if !xml.match(/xml\">/) then
clean_dita(xml)
else
if xml.match (/xml\">/) then
xml.gsub!(/xml\">./,"xml" )
@autoclose = "false"
elsif xml.match (/xml\".*?\/>/)
xml.gsub!(/xml\".*?\/>/, "xml")
@autoclose = "true"
else # no matches so I have to do some cleanup on the string
xml.gsub!(/xml\".*?>/, "xml")
@autoclose = "false"
end
end
end
def clean_dita (xml)
begin
if xml.match (/dita\">/) then
xml.gsub!(/dita\">./,"dita" )
@autoclose = "false"
elsif xml.match (/dita\".*?\/>/)
xml.gsub!(/dita\".*?\/>/, "dita")
@autoclose = "true"
else # no matches so I have to do some cleanup on the string
xml.gsub!(/dita\".*?>/, "dita")
@autoclose = "false"
end
end
end
directorypath = ARGV[0]
if directorypath.nil?
directorypath = Dir.pwd
directorypath = "/Users/wayne/Dropbox/add_navtitles/nav_test/ruby_script_test/"
end
filelist = Dir.entries(directorypath).join(' ')
filelist = filelist.split(' ').grep(/\.ditamap/)
puts "\nFile Directory: #{directorypath}\n\n"
missing_files = Array.new
count = 0
Dir::mkdir("#{directorypath}/backup_ditamaps") unless File.exists?("#{directorypath}/backup_ditamaps")
puts "Maps in Directory:\n"
filelist.each do |the_map|
puts "#{the_map}\n"
input_dir = "#{directorypath}/#{the_map}"
output_dir = "#{directorypath}/backup_ditamaps/"
FileUtils.cp input_dir, output_dir
end
puts "\n\n"
filelist.each do |a_ditamap|
fileName = "#{directorypath}/#{a_ditamap}"
f = File.open("#{fileName}", 'r')
ditamp_file_utf = f.read
f.close
add_returns = ditamp_file_utf.to_s.gsub(/>\s+?</, ">_split_<")
@mapcontents = add_returns.split("_split_") # store contents into an array
if @mapcontents.count == 1
@mapcontents = add_returns.split("\r")
end
if @mapcontents.count == 1
add_returns = ditamp_file_utf.to_s.gsub(/></, ">_split_<")
@mapcontents = add_returns.split("_split_")
end
@touched_lines = 0
@not_touched = 0
@mapcontents.each_with_index do |mapline, index|
@autoclose = "false"
if mapline.match(/(\.xml|\.dita)/) and mapline.match(/\<topicref/) # Look only for .xml or .dita files, ignore other lines in array
if mapline.match(/navtitle/) then # if title already exists do nothing!
@not_touched +=1
else
replacement_line = mapline
cleanup(replacement_line)
search_line = mapline.gsub(/<topic.*href=\"/, "")
removeattributes(search_line)
just_file_name = search_line
search_line = "#{directorypath}/#{search_line}"
if search_line.match(/\"<\/topicref>/) then # Special case, not normally used.
search_line.gsub!(/\"<\/topicref>/, "")
end
begin
filecontents = File.read(search_line) # Open file up to read title
file_xml_contents = Nokogiri::XML(filecontents) # Parse XML with Xpath
title = file_xml_contents.xpath('//title/text()').to_s
title = just_file_name if title.nil?
title.strip!
if @autoclose.match("false")
# @mapcontents[index] = replacement_line + "\" navtitle=\"" + title + "\" locktitle=\"yes\">" # put back into array
@mapcontents[index] = "#{replacement_line} \" locktitle=\"yes\"><topicmeta><navtitle>#{title}</navtitle></topicmeta>" # put back into array
elsif @autoclose.match("true")
# @mapcontents[index] = replacement_line + "\" navtitle=\"" + title + "\" locktitle=\"yes\" \/>" # put back into array
@mapcontents[index] = "#{replacement_line} \" locktitle=\"yes\"><topicmeta><navtitle>#{title}</navtitle></topicmeta></topicref>" # put back into array
end
@touched_lines +=1
@autoclose = "false"
rescue Exception
missing_files << "#{search_line}\n\r"
end
end # end of mapline.match /navtitle/
end # end of mapline.match.xml
end # end of mapcontents.each
# Write out file here
filecontents = @mapcontents.join.to_s
@mapcontents.clear
xsl =<<XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
XSL
doc = Nokogiri::XML(filecontents)
xslt = Nokogiri::XSLT(xsl)
out = xslt.transform(doc)
filecontents= out.to_xml
File.open(fileName, 'w+') {|f| f.write(filecontents) }
puts "Added navtitle to #{@touched_lines} topics in ditamap:\n #{fileName} : #{@not_touched} topics with navtitles already and not touched. \n"
touched_lines = 0
end
if !missing_files.count == 0
puts "Missing XML Files: \n#{missing_files.join.to_s}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment