Initial import
This commit is contained in:
parent
ea6a546f97
commit
e95bc01469
9 changed files with 581 additions and 0 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -31,3 +31,6 @@ DerivedData
|
||||||
# Carthage/Checkouts
|
# Carthage/Checkouts
|
||||||
|
|
||||||
Carthage/Build
|
Carthage/Build
|
||||||
|
|
||||||
|
# DS_Store
|
||||||
|
.DS_Store
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "CommandLine"]
|
||||||
|
path = CommandLine
|
||||||
|
url = https://github.com/jatoben/CommandLine.git
|
1
CommandLine
Submodule
1
CommandLine
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7a8323d3a037c0a0d82c6cf734b46d98da10498a
|
60
README.md
Normal file
60
README.md
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
opml2html
|
||||||
|
=========
|
||||||
|
|
||||||
|
### What is this? (aka the Problem to be Solved)
|
||||||
|
|
||||||
|
O HAI
|
||||||
|
Need stuff here
|
||||||
|
|
||||||
|
[NosillaCast][NC]
|
||||||
|
[Omni Group][OMNI]
|
||||||
|
[OmniOutliner][OO]
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: opml2html [options]
|
||||||
|
-f, --input-file:
|
||||||
|
Path to the input file. (Required)
|
||||||
|
-o, --output-file:
|
||||||
|
Path to the output file. (Optional, default = <filename without extension>.html)
|
||||||
|
-l, --full-mode:
|
||||||
|
Create full HTML output (including <head>, etc.)
|
||||||
|
-h, --help:
|
||||||
|
Prints a help message.
|
||||||
|
```
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
This software is licensed under the terms of the [MIT License][MIT].
|
||||||
|
|
||||||
|
Copyright (c) 2015 Donald Burr <[dburr@DonaldBurr.com][EMAIL]>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
### Credits
|
||||||
|
|
||||||
|
Uses Ben Gollmer's Swift [CommandLine][CL] library.
|
||||||
|
|
||||||
|
[NC]: http://podfeet.com/ "NosillaCast"
|
||||||
|
[OMNI]: https://www.omnigroup.com "The Omni Group"
|
||||||
|
[OO]: https://www.omnigroup.com/omnioutliner "OmniOutliner"
|
||||||
|
[EMAIL]: mailto:dburr@DonaldBurr.com?subject=opml2html "Email"
|
||||||
|
[MIT]: http://opensource.org/licenses/MIT "MIT License"
|
||||||
|
[CL]: https://github.com/jatoben/CommandLine "CommandLine"
|
BIN
bin/opml2html
Executable file
BIN
bin/opml2html
Executable file
Binary file not shown.
260
opml2html.xcodeproj/project.pbxproj
Normal file
260
opml2html.xcodeproj/project.pbxproj
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
EA273E611B7D0E810083B1C5 /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA273E5E1B7D0E810083B1C5 /* CommandLine.swift */; };
|
||||||
|
EA273E621B7D0E810083B1C5 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA273E5F1B7D0E810083B1C5 /* Option.swift */; };
|
||||||
|
EA273E631B7D0E810083B1C5 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA273E601B7D0E810083B1C5 /* StringExtensions.swift */; };
|
||||||
|
EA37B3E91B7C6A970025B496 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA37B3E81B7C6A970025B496 /* main.swift */; };
|
||||||
|
EA37B3F01B7C6D7C0025B496 /* ParseEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA37B3EF1B7C6D7C0025B496 /* ParseEngine.swift */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
EA37B3E31B7C6A970025B496 /* CopyFiles */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 0;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
EA273E5E1B7D0E810083B1C5 /* CommandLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommandLine.swift; path = ../CommandLine/CommandLine/CommandLine.swift; sourceTree = "<group>"; };
|
||||||
|
EA273E5F1B7D0E810083B1C5 /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Option.swift; path = ../CommandLine/CommandLine/Option.swift; sourceTree = "<group>"; };
|
||||||
|
EA273E601B7D0E810083B1C5 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringExtensions.swift; path = ../CommandLine/CommandLine/StringExtensions.swift; sourceTree = "<group>"; };
|
||||||
|
EA37B3E51B7C6A970025B496 /* opml2html */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = opml2html; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
EA37B3E81B7C6A970025B496 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
|
EA37B3EF1B7C6D7C0025B496 /* ParseEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseEngine.swift; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
EA37B3E21B7C6A970025B496 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
EA37B3DC1B7C6A970025B496 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
EA37B3E71B7C6A970025B496 /* opml2html */,
|
||||||
|
EA37B3E61B7C6A970025B496 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
EA37B3E61B7C6A970025B496 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
EA37B3E51B7C6A970025B496 /* opml2html */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
EA37B3E71B7C6A970025B496 /* opml2html */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
EA37B3E81B7C6A970025B496 /* main.swift */,
|
||||||
|
EA37B3EF1B7C6D7C0025B496 /* ParseEngine.swift */,
|
||||||
|
EA273E5E1B7D0E810083B1C5 /* CommandLine.swift */,
|
||||||
|
EA273E5F1B7D0E810083B1C5 /* Option.swift */,
|
||||||
|
EA273E601B7D0E810083B1C5 /* StringExtensions.swift */,
|
||||||
|
);
|
||||||
|
path = opml2html;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
EA37B3E41B7C6A970025B496 /* opml2html */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = EA37B3EC1B7C6A970025B496 /* Build configuration list for PBXNativeTarget "opml2html" */;
|
||||||
|
buildPhases = (
|
||||||
|
EA37B3E11B7C6A970025B496 /* Sources */,
|
||||||
|
EA37B3E21B7C6A970025B496 /* Frameworks */,
|
||||||
|
EA37B3E31B7C6A970025B496 /* CopyFiles */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = opml2html;
|
||||||
|
productName = opml2html;
|
||||||
|
productReference = EA37B3E51B7C6A970025B496 /* opml2html */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
EA37B3DD1B7C6A970025B496 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0640;
|
||||||
|
ORGANIZATIONNAME = "Donald Burr";
|
||||||
|
TargetAttributes = {
|
||||||
|
EA37B3E41B7C6A970025B496 = {
|
||||||
|
CreatedOnToolsVersion = 6.4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = EA37B3E01B7C6A970025B496 /* Build configuration list for PBXProject "opml2html" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = EA37B3DC1B7C6A970025B496;
|
||||||
|
productRefGroup = EA37B3E61B7C6A970025B496 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
EA37B3E41B7C6A970025B496 /* opml2html */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
EA37B3E11B7C6A970025B496 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
EA273E621B7D0E810083B1C5 /* Option.swift in Sources */,
|
||||||
|
EA273E611B7D0E810083B1C5 /* CommandLine.swift in Sources */,
|
||||||
|
EA273E631B7D0E810083B1C5 /* StringExtensions.swift in Sources */,
|
||||||
|
EA37B3E91B7C6A970025B496 /* main.swift in Sources */,
|
||||||
|
EA37B3F01B7C6D7C0025B496 /* ParseEngine.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
EA37B3EA1B7C6A970025B496 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
EA37B3EB1B7C6A970025B496 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
EA37B3ED1B7C6A970025B496 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
EA37B3EE1B7C6A970025B496 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
EA37B3E01B7C6A970025B496 /* Build configuration list for PBXProject "opml2html" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
EA37B3EA1B7C6A970025B496 /* Debug */,
|
||||||
|
EA37B3EB1B7C6A970025B496 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
EA37B3EC1B7C6A970025B496 /* Build configuration list for PBXNativeTarget "opml2html" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
EA37B3ED1B7C6A970025B496 /* Debug */,
|
||||||
|
EA37B3EE1B7C6A970025B496 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = EA37B3DD1B7C6A970025B496 /* Project object */;
|
||||||
|
}
|
7
opml2html.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
opml2html.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:opml2html.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
156
opml2html/ParseEngine.swift
Normal file
156
opml2html/ParseEngine.swift
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
//
|
||||||
|
// ParseEngine.swift
|
||||||
|
// opml2html
|
||||||
|
//
|
||||||
|
// Created by Donald Burr on 8/12/15.
|
||||||
|
// Copyright (c) 2015 Donald Burr. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
protocol ParseEngineDelegate {
|
||||||
|
func parseDidSucceed(output: String)
|
||||||
|
func parseDidFail(error: NSError)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParseEngine : NSObject, NSXMLParserDelegate {
|
||||||
|
var parser: NSXMLParser?
|
||||||
|
var currentElementText: String = ""
|
||||||
|
var level: Int = 0
|
||||||
|
var fullOutput: Bool = false
|
||||||
|
var parseOutput: String = ""
|
||||||
|
var delegate: ParseEngineDelegate?
|
||||||
|
var validChars: NSMutableCharacterSet
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.validChars = NSMutableCharacterSet(charactersInString: " ")
|
||||||
|
self.validChars.formUnionWithCharacterSet(NSCharacterSet.URLPathAllowedCharacterSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
init(delegate: ParseEngineDelegate) {
|
||||||
|
self.delegate = delegate
|
||||||
|
self.validChars = NSMutableCharacterSet(charactersInString: " ")
|
||||||
|
self.validChars.formUnionWithCharacterSet(NSCharacterSet.URLPathAllowedCharacterSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setup() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(#path: String, fullOutput: Bool) {
|
||||||
|
self.fullOutput = fullOutput
|
||||||
|
if !NSFileManager.defaultManager().fileExistsAtPath(path) {
|
||||||
|
if let delegate = delegate {
|
||||||
|
let userInfo: [String:String] =
|
||||||
|
[
|
||||||
|
NSLocalizedDescriptionKey: "Operation was unsuccessful.",
|
||||||
|
NSLocalizedFailureReasonErrorKey: "File does not exist.",
|
||||||
|
NSLocalizedRecoverySuggestionErrorKey: "Check the filename."
|
||||||
|
]
|
||||||
|
|
||||||
|
let error = NSError(domain: "ParseEngineErrorDomain", code: 1, userInfo: userInfo)
|
||||||
|
delegate.parseDidFail(error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let fileUrl = NSURL(fileURLWithPath: path)
|
||||||
|
parser = NSXMLParser(contentsOfURL: fileUrl)
|
||||||
|
if let p = parser {
|
||||||
|
p.delegate = self
|
||||||
|
if !p.parse() {
|
||||||
|
if let delegate = delegate {
|
||||||
|
let userInfo: [String:String] =
|
||||||
|
[
|
||||||
|
NSLocalizedDescriptionKey: "Operation was unsuccessful.",
|
||||||
|
NSLocalizedFailureReasonErrorKey: "Parser failed to parse file.",
|
||||||
|
NSLocalizedRecoverySuggestionErrorKey: "Check to make sure that the OPML file syntax is correct."
|
||||||
|
]
|
||||||
|
let error = NSError(domain: "ParseEngineErrorDomain", code: 2, userInfo: userInfo)
|
||||||
|
delegate.parseDidFail(error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let delegate = delegate {
|
||||||
|
let userInfo: [String:String] =
|
||||||
|
[
|
||||||
|
NSLocalizedDescriptionKey: "Operation was unsuccessful.",
|
||||||
|
NSLocalizedFailureReasonErrorKey: "Parser failed to initialize.",
|
||||||
|
NSLocalizedRecoverySuggestionErrorKey: "Check to make sure that the OPML file syntax is correct."
|
||||||
|
]
|
||||||
|
let error = NSError(domain: "ParseEngineErrorDomain", code: 2, userInfo: userInfo)
|
||||||
|
delegate.parseDidFail(error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {
|
||||||
|
if (elementName == "outline") {
|
||||||
|
let outlineText: String = attributeDict["text"] as! String
|
||||||
|
let saneText = saneify(outlineText)
|
||||||
|
addParsedText("<UL>\n")
|
||||||
|
addParsedText("<LI>\(saneText)</LI>\n")
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parser(parser: NSXMLParser, foundCharacters string: String?) {
|
||||||
|
if let string = string {
|
||||||
|
currentElementText += string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
|
||||||
|
let saneText = saneify(currentElementText)
|
||||||
|
|
||||||
|
if (elementName == "title") {
|
||||||
|
if (fullOutput) {
|
||||||
|
addParsedText("<HTML>\n<HEAD>\n<TITLE>\(saneText)</TITLE>\n</HEAD>\n<BODY>\n")
|
||||||
|
}
|
||||||
|
addParsedText("<H1>\(saneText)</H1>\n")
|
||||||
|
currentElementText = ""
|
||||||
|
} else if (elementName == "outline") {
|
||||||
|
addParsedText("</UL>\n")
|
||||||
|
level--;
|
||||||
|
if (level == 0 && fullOutput) {
|
||||||
|
addParsedText("</BODY>\n</HTML>\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parserDidEndDocument(parser: NSXMLParser) {
|
||||||
|
if let delegate = delegate {
|
||||||
|
delegate.parseDidSucceed(parseOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
|
||||||
|
if let delegate = delegate {
|
||||||
|
let userInfo: [String:String] =
|
||||||
|
[
|
||||||
|
NSLocalizedDescriptionKey: "Parse Failed.",
|
||||||
|
NSLocalizedFailureReasonErrorKey: "Parse Error #\(parseError.code): \(parseError.localizedDescription)",
|
||||||
|
NSLocalizedRecoverySuggestionErrorKey: "Check the validity of your XML."
|
||||||
|
]
|
||||||
|
let error = NSError(domain: "ParseEngineErrorDomain", code: 3, userInfo: userInfo)
|
||||||
|
delegate.parseDidFail(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addParsedText(text: String) {
|
||||||
|
parseOutput += text
|
||||||
|
}
|
||||||
|
|
||||||
|
private func saneify(string: String) -> String {
|
||||||
|
// let escapedText = currentElementText.stringByAddingPercentEncodingWithAllowedCharacters(self.validChars)!
|
||||||
|
// let escapedText = currentElementText.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
|
||||||
|
|
||||||
|
let string1 = string.stringByReplacingOccurrencesOfString("’", withString: "'", options: NSStringCompareOptions.LiteralSearch, range: nil)
|
||||||
|
if (string1.rangeOfString("http") != nil) {
|
||||||
|
return "<A HREF=\"\(string1)\">\(string1)</A>"
|
||||||
|
} else {
|
||||||
|
return string1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
opml2html/main.swift
Normal file
91
opml2html/main.swift
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
//
|
||||||
|
// main.swift
|
||||||
|
// opml2html
|
||||||
|
//
|
||||||
|
// Created by Donald Burr on 8/12/15.
|
||||||
|
// Copyright (c) 2015 Donald Burr. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
var full: Bool = false
|
||||||
|
var fileName: String?
|
||||||
|
|
||||||
|
let cli = CommandLine()
|
||||||
|
|
||||||
|
class Handler: NSObject, ParseEngineDelegate {
|
||||||
|
var fileName: String?
|
||||||
|
let parseEngine = ParseEngine()
|
||||||
|
|
||||||
|
func process(#inFile: String, outFile: String, fullOutput: Bool) {
|
||||||
|
parseEngine.delegate = self
|
||||||
|
println("Operating on file: \(inFile)")
|
||||||
|
print("Saving to file: \(outFile)")
|
||||||
|
if (fullOutput) {
|
||||||
|
println(" (full mode)")
|
||||||
|
} else {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
self.fileName = outFile
|
||||||
|
parseEngine.parse(path: inFile, fullOutput: fullOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDidSucceed(output: String) {
|
||||||
|
if let fileName = fileName {
|
||||||
|
output.writeToFile(fileName, atomically: true, encoding: NSUTF8StringEncoding, error: nil)
|
||||||
|
} else {
|
||||||
|
println(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDidFail(error: NSError) {
|
||||||
|
println("Parse Failed: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = Handler()
|
||||||
|
|
||||||
|
let filePath = StringOption(shortFlag: "f", longFlag: "input-file", required: true,
|
||||||
|
helpMessage: "Path to the input file. (Required)")
|
||||||
|
let outputFilePath = StringOption(shortFlag: "o", longFlag: "output-file", required: false,
|
||||||
|
helpMessage: "Path to the output file. (Optional, default = <filename without extension>.html)")
|
||||||
|
let fullMode = BoolOption(shortFlag: "l", longFlag: "full-mode",
|
||||||
|
helpMessage: "Create full HTML output (including <head>, etc.)")
|
||||||
|
let help = BoolOption(shortFlag: "h", longFlag: "help",
|
||||||
|
helpMessage: "Prints a help message.")
|
||||||
|
|
||||||
|
cli.addOptions(filePath, outputFilePath, fullMode, help)
|
||||||
|
|
||||||
|
let (success, error) = cli.parse()
|
||||||
|
if !success {
|
||||||
|
println(error!)
|
||||||
|
cli.printUsage()
|
||||||
|
exit(EX_USAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
full = fullMode.value
|
||||||
|
|
||||||
|
if let fn = filePath.value {
|
||||||
|
if let saveFile = outputFilePath.value {
|
||||||
|
handler.process(inFile: fn, outFile: saveFile, fullOutput: full)
|
||||||
|
} else {
|
||||||
|
let saveFile = fn.stringByDeletingPathExtension.stringByAppendingPathExtension("html")!
|
||||||
|
handler.process(inFile: fn, outFile: saveFile, fullOutput: full)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("Error: no file name specified")
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
for argument in Process.arguments {
|
||||||
|
switch argument {
|
||||||
|
case "--full":
|
||||||
|
println("Full mode enabled")
|
||||||
|
full = true
|
||||||
|
|
||||||
|
default:
|
||||||
|
println("an argument: \(argument)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Add table
Add a link
Reference in a new issue