├── CSSSelectorConverter ├── en.lproj │ └── InfoPlist.strings ├── CSSSelectorParser.plist ├── IGMasterViewController.h ├── CSSBaseSelector.h ├── CSSSelectorConverter.h ├── IGAppDelegate.h ├── CSSIDSelector.h ├── CSSTypeSelector.h ├── CSSClassSelector.h ├── CSSUniversalSelector.h ├── CSSPseudoClass.h ├── CSSSelectorConverter-Prefix.pch ├── main.m ├── CSSSelectorTokeniser.h ├── CSSBaseSelector.m ├── IGDetailViewController.h ├── CSSNamedSelector.h ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── CSSSelectorGroup.h ├── CSSNamedSelector.m ├── CSSSelectorAttribute.h ├── CSSSelectorGrammar.h ├── CSSSelectors.h ├── CSSCombinator.h ├── CSSPseudoClass.m ├── CSSUniversalSelector.m ├── CSSSelectorSequence.h ├── CSSSelectorAttributeOperator.h ├── CSSIDSelector.m ├── CSSTypeSelector.m ├── CSSClassSelector.m ├── CSSSelectorXPathVisitor.h ├── CSSSelectorToXPathConverter.h ├── CSSSelectorAttribute.m ├── IGDetailViewController.m ├── CSSSelectorParser.h ├── CSSSelectorToXPathConverter.m ├── CSSSelectorGroup.m ├── CSSSelectorConverter-Info.plist ├── CSSSelectorGrammar.txt ├── CSSSelectorGrammar.m ├── CSSSelectors.m ├── CSSSelectorAttributeOperator.m ├── IGAppDelegate.m ├── CSSSelectorSequence.m ├── CSSCombinator.m ├── CSSSelectorParser.m ├── IGMasterViewController.m ├── CSSSelectorTokeniser.m ├── CSSSelectorXPathVisitor.m └── Base.lproj │ └── Main.storyboard ├── CSSSelectorConverterTests ├── en.lproj │ └── InfoPlist.strings ├── CSSSelectorConverterTests-Info.plist ├── CSSSelectorParserSpec.m ├── CSSToXPathConverterSpec.m ├── CSSSelectorXPathVisitorSpec.m └── CSSSelectorTokeniserSpec.m ├── .gitignore ├── Podfile ├── Rakefile ├── CSSSelectorConverter.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── CSSSelectorConverter.xcscmblueprint │ └── CSSSelectorConverter.xccheckout ├── CSSSelectorConverter.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── CSSSelectorConverter.xcscheme └── project.pbxproj ├── .travis.yml ├── CHANGELOG.md ├── Podfile.lock ├── LICENSE.txt ├── bin └── CSSSelectorParserGenerator.m ├── CSSSelectorConverter.podspec └── README.md /CSSSelectorConverter/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Pods 3 | CSSSelectorConverter.xcodeproj/xcuserdata 4 | CSSSelectorConverter.xcworkspace/xcuserdata -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorParser.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siuying/CSSSelectorConverter/HEAD/CSSSelectorConverter/CSSSelectorParser.plist -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.0' 2 | 3 | pod 'CocoaLumberjack', '~> 2.0' 4 | pod 'NUIParse' 5 | 6 | target :'CSSSelectorConverterTests' do 7 | pod 'Kiwi', '>= 2.3.0' 8 | end -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | 4 | desc "Run tests" 5 | task :test do 6 | system("xcodebuild -workspace CSSSelectorConverter.xcworkspace -scheme CSSSelectorConverter -sdk iphonesimulator test") 7 | end -------------------------------------------------------------------------------- /CSSSelectorConverter.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CSSSelectorConverter.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2.2.3 2 | language: objective-c 3 | before_script: 4 | - export LANG=en_US.UTF-8 5 | - gem install xcpretty cocoapods 6 | - pod install 7 | script: xcodebuild -workspace CSSSelectorConverter.xcworkspace -scheme CSSSelectorConverter -sdk iphonesimulator test | xcpretty -c; exit ${PIPESTATUS[0]} 8 | -------------------------------------------------------------------------------- /CSSSelectorConverter/IGMasterViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // IGMasterViewController.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface IGMasterViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSBaseSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSBaseSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CSSBaseSelector : NSObject 12 | 13 | +(instancetype) selector; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorConverter.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #ifndef _CSSSelectorConverter_ 10 | #define _CSSSelectorConverter_ 11 | 12 | #import "CSSSelectorToXPathConverter.h" 13 | #endif 14 | -------------------------------------------------------------------------------- /CSSSelectorConverter/IGAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // IGAppDelegate.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface IGAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSIDSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSIDSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSNamedSelector.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSIDSelector : CSSNamedSelector 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSTypeSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSTypeSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSNamedSelector.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSTypeSelector : CSSNamedSelector 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSClassSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSClassSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSNamedSelector.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSClassSelector : CSSNamedSelector 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSUniversalSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSUniversalSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSTypeSelector.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSUniversalSelector : CSSTypeSelector 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSPseudoClass.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSPseudoClass.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSNamedSelector.h" 10 | #import "NUIPParser.h" 11 | 12 | @interface CSSPseudoClass : CSSNamedSelector 13 | 14 | @property (nonatomic, weak) CSSNamedSelector* parent; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorConverter-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif -------------------------------------------------------------------------------- /CSSSelectorConverter/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "IGAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([IGAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorTokeniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorTokeniser.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "NUIPTokeniser.h" 10 | 11 | /** 12 | * Tokenize the CSS Selector for the CSSSelectorGrammar to consume. 13 | * 14 | * @see CSSSelectorGrammar 15 | */ 16 | @interface CSSSelectorTokeniser : NUIPTokeniser 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSBaseSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSBaseSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSBaseSelector.h" 10 | 11 | @implementation CSSBaseSelector 12 | 13 | -(NSString*) description { 14 | return @""; 15 | } 16 | 17 | +(instancetype) selector { 18 | return [[self alloc] init]; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CSSSelectorConverter/IGDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // IGDetailViewController.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface IGDetailViewController : UIViewController 12 | 13 | @property (strong, nonatomic) id detailItem; 14 | 15 | @property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel; 16 | @end 17 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSNamedSelector.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSNamedSelector.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSBaseSelector.h" 11 | 12 | @interface CSSNamedSelector : CSSBaseSelector 13 | 14 | @property (nonatomic, copy) NSString* name; 15 | 16 | +(instancetype) selectorWithName:(NSString*)name; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CSSSelectorConverter/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorGroup.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSBaseSelector.h" 10 | #import "CSSSelectors.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSSelectorGroup : CSSBaseSelector 14 | 15 | @property (nonatomic, strong) NSMutableArray* selectors; 16 | 17 | -(void) addSelectors:(CSSSelectors*)selectors; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | --------- 3 | 4 | 1.2.1 5 | ----- 6 | 7 | - Added [CSSSelectorToXPathConverter sharedConverter]. 8 | 9 | 1.2.0 10 | ----- 11 | 12 | - Update podspec to only expose minimal files. 13 | 14 | 1.1.2 15 | ----- 16 | 17 | - Use NUIParse. 18 | 19 | 1.1.0 (28/01/2014) 20 | ------------------ 21 | 22 | - Fix #1, properly handle selector sequence. 23 | * Use [CoreParse](https://github.com/beelsebob/CoreParse) instead of [ParseKit](https://github.com/itod/parsekit) as parser generator. 24 | 25 | 1.0.0 (09/01/2014) 26 | -------------- 27 | 28 | + Initial version. -------------------------------------------------------------------------------- /CSSSelectorConverter/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSNamedSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSNamedSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSNamedSelector.h" 10 | 11 | @implementation CSSNamedSelector 12 | 13 | +(instancetype) selectorWithName:(NSString*)name { 14 | CSSNamedSelector* selector = [[self alloc] init]; 15 | selector.name = name; 16 | return selector; 17 | } 18 | 19 | -(NSString*) description { 20 | return [NSString stringWithFormat:@"", _name]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorAttribute.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorAttribute.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSBaseSelector.h" 10 | #import "CSSSelectorAttributeOperator.h" 11 | #import "NUIPParser.h" 12 | 13 | @interface CSSSelectorAttribute : CSSBaseSelector 14 | 15 | @property (nonatomic, strong) CSSSelectorAttributeOperator* attributeOperator; 16 | @property (nonatomic, copy) NSString* name; 17 | @property (nonatomic, copy) NSString* value; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorGrammar.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorGrammar.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "NUIPGrammar.h" 10 | 11 | @interface CSSSelectorGrammar : NUIPGrammar 12 | 13 | /** 14 | * Create a Grammar object using the grammar file in the bundle. 15 | */ 16 | -(instancetype) init; 17 | 18 | /** 19 | * Create a Grammar object using the grammar file supplied. 20 | * @param path Path to the grammar defintion 21 | */ 22 | -(instancetype) initWithPath:(NSString*)path; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectors.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectors.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSBaseSelector.h" 10 | #import "NUIPParser.h" 11 | 12 | @interface CSSSelectors : CSSBaseSelector 13 | 14 | @property (nonatomic, strong) NSMutableArray* selectors; 15 | 16 | /** 17 | Add a CSSSelectorSequence or CSSCombinator to the selectors. 18 | 19 | @raise NSInvalidArgumentException if selector is not CSSSelectorSequence or CSSCombinator 20 | */ 21 | -(void) addSelector:(CSSBaseSelector*)selector; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSCombinator.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSCombinator.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSBaseSelector.h" 10 | #import "NUIPParser.h" 11 | 12 | typedef NS_ENUM(NSInteger, CSSCombinatorType) { 13 | CSSCombinatorTypeNone = 0, 14 | CSSCombinatorTypeDescendant, 15 | CSSCombinatorTypeAdjacent, 16 | CSSCombinatorTypeGeneralSibling 17 | }; 18 | 19 | @interface CSSCombinator : CSSBaseSelector 20 | 21 | @property (nonatomic, assign) CSSCombinatorType type; 22 | 23 | +(CSSCombinator*) noneCombinator; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CocoaLumberjack (2.2.0): 3 | - CocoaLumberjack/Default (= 2.2.0) 4 | - CocoaLumberjack/Extensions (= 2.2.0) 5 | - CocoaLumberjack/Core (2.2.0) 6 | - CocoaLumberjack/Default (2.2.0): 7 | - CocoaLumberjack/Core 8 | - CocoaLumberjack/Extensions (2.2.0): 9 | - CocoaLumberjack/Default 10 | - Kiwi (2.4.0) 11 | - NUIParse (1.3) 12 | 13 | DEPENDENCIES: 14 | - CocoaLumberjack (~> 2.0) 15 | - Kiwi (>= 2.3.0) 16 | - NUIParse 17 | 18 | SPEC CHECKSUMS: 19 | CocoaLumberjack: 17fe8581f84914d5d7e6360f7c70022b173c3ae0 20 | Kiwi: f49c9d54b28917df5928fe44968a39ed198cb8a8 21 | NUIParse: 2e3885ba7807477266396292626bd387d34c2338 22 | 23 | COCOAPODS: 0.39.0 24 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSPseudoClass.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSPseudoClass.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | #import "CSSPseudoClass.h" 9 | #import "NUIParse.h" 10 | 11 | @implementation CSSPseudoClass 12 | 13 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 14 | self = [self init]; 15 | 16 | id token = [syntaxTree valueForTag:@"className"]; 17 | if ([token isIdentifierToken]) { 18 | self.name = [token identifier]; 19 | } 20 | 21 | return self; 22 | } 23 | 24 | -(NSString*) description { 25 | return [NSString stringWithFormat:@"", self.name]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSUniversalSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSUniversalSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSUniversalSelector.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSUniversalSelector 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | return [self init]; 16 | } 17 | 18 | - (id)init { 19 | self = [super init]; 20 | self.name = @"*"; 21 | return self; 22 | } 23 | 24 | +(instancetype) selector { 25 | return [self selectorWithName:@"*"]; 26 | } 27 | 28 | -(NSString*) description { 29 | return @""; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorSequence.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorSequence.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSBaseSelector.h" 11 | #import "NUIPParser.h" 12 | 13 | @class CSSCombinator; 14 | @class CSSPseudoClass; 15 | @class CSSTypeSelector; 16 | 17 | @interface CSSSelectorSequence : CSSBaseSelector 18 | 19 | @property (nonatomic, strong) CSSPseudoClass* pseudoClass; 20 | 21 | @property (nonatomic, strong) CSSTypeSelector* universalOrTypeSelector; 22 | 23 | @property (nonatomic, strong) NSMutableArray* otherSelectors; 24 | 25 | -(void) addSelector:(CSSBaseSelector*)selector; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/CSSSelectorConverterTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | hk.ignition.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorAttributeOperator.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorAttributeType.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSNamedSelector.h" 10 | #import "NUIPParser.h" 11 | 12 | typedef NS_ENUM(NSInteger, CSSSelectorAttributeOperatorType) { 13 | CSSSelectorAttributeOperatorTypeNone = 0, 14 | CSSSelectorAttributeOperatorTypeEqual, 15 | CSSSelectorAttributeOperatorTypeIncludes, 16 | CSSSelectorAttributeOperatorTypeDash 17 | }; 18 | 19 | @interface CSSSelectorAttributeOperator : CSSNamedSelector 20 | 21 | @property (nonatomic, assign) CSSSelectorAttributeOperatorType attributeOperator; 22 | 23 | +(CSSSelectorAttributeOperatorType) operatorWithString:(NSString*) type; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSIDSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSIDSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSIDSelector.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSIDSelector 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | self = [self init]; 16 | if (self) { 17 | NSArray *components = [syntaxTree children]; 18 | if ([components count] == 2) { 19 | NUIPIdentifierToken* token = components[1]; 20 | if ([token isIdentifierToken]) { 21 | self.name = [token identifier]; 22 | } 23 | } 24 | } 25 | return self; 26 | } 27 | 28 | -(NSString*) description { 29 | return [NSString stringWithFormat:@"", self.name]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSTypeSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSTypeSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSTypeSelector.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSTypeSelector 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | self = [self init]; 16 | if (self) { 17 | NSArray *components = [syntaxTree children]; 18 | if ([components count] == 1) { 19 | NUIPIdentifierToken* token = components[0]; 20 | if ([token isIdentifierToken]) { 21 | self.name = [token identifier]; 22 | } 23 | } 24 | } 25 | return self; 26 | } 27 | 28 | -(NSString*) description { 29 | return [NSString stringWithFormat:@"", self.name]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSClassSelector.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSClassSelector.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSClassSelector.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSClassSelector 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | self = [self init]; 16 | if (self) { 17 | NSArray *components = [syntaxTree children]; 18 | if ([components count] == 2) { 19 | NUIPIdentifierToken* token = components[1]; 20 | if ([token isIdentifierToken]) { 21 | self.name = [token identifier]; 22 | } 23 | } 24 | } 25 | return self; 26 | } 27 | 28 | -(NSString*) description { 29 | return [NSString stringWithFormat:@"", self.name]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorXPathVisitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorXPathVisitor.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CSSBaseSelector; 12 | 13 | /** 14 | * Walk a tree of CSSBaseSelector subclasses, and build a XPath representation of the CSS. 15 | * 16 | * Upon finish, invoke xpathString to get the XPath. 17 | */ 18 | @interface CSSSelectorXPathVisitor : NSObject 19 | 20 | 21 | /** 22 | * Visit a selector node (CSSBaseSelector subclasses) and generate XPath representation of the CSS Selector. 23 | * 24 | * @param node A CSSBaseSelector subclasses. 25 | * @throw NSInvalidArgumentException if the class is not supported by the visitor. 26 | */ 27 | -(void) visit:(CSSBaseSelector*)node; 28 | 29 | /** 30 | * @return Returns XPath representation of the CSS Selector. 31 | */ 32 | -(NSString*) xpathString; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorToXPathConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSSToXPathConverter.h 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CSSSelectorParser; 12 | 13 | /** 14 | * Convert a CSS Selector to XPath. 15 | * 16 | * @see CSSSelectorParser 17 | * @see CSSSelectorXPathVisitor 18 | */ 19 | @interface CSSSelectorToXPathConverter : NSObject 20 | 21 | @property (nonatomic, strong) CSSSelectorParser* parser; 22 | 23 | +(instancetype) sharedConverter; 24 | 25 | -(id) init; 26 | 27 | -(id) initWithParser:(CSSSelectorParser*)parser; 28 | 29 | /** 30 | * Parse a CSS Selector and return a XPath string. 31 | * 32 | * 33 | * @param css The css selector 34 | * @param error If the parse failed and parser return nil, error is set to last known error. 35 | * @return XPath representation of the given CSS Selector. 36 | */ 37 | -(NSString*)xpathWithCSS:(NSString*)css error:(NSError*__autoreleasing*)error; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Francis Chong, Ignition Soft. All rights reserved. 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | 9 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorAttribute.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorAttribute.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSSelectorParser.h" 10 | #import "CSSSelectorAttribute.h" 11 | #import "NUIParse.h" 12 | 13 | @implementation CSSSelectorAttribute 14 | 15 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 16 | self = [self init]; 17 | if (self) { 18 | self.attributeOperator = [syntaxTree valueForTag:@"op"]; 19 | self.name = [[syntaxTree valueForTag:@"attrName"] identifier]; 20 | 21 | NSArray* valChildren = [[syntaxTree valueForTag:@"attrValue"] children]; 22 | if (valChildren) { 23 | if ([valChildren count] == 1 && [valChildren[0] isQuotedToken]) { 24 | self.value = [valChildren[0] content]; 25 | } 26 | } 27 | } 28 | return self; 29 | } 30 | 31 | -(NSString*) description { 32 | return [NSString stringWithFormat:@"", self.name, self.attributeOperator.name, self.value]; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /bin/CSSSelectorParserGenerator.m: -------------------------------------------------------------------------------- 1 | /* 2 | podfile-start 3 | platform :osx, '10.9' 4 | pod 'CSSSelectorConverter', :local => '/Users/siuying/workspace/opensource/CSSSelectorConverter' 5 | podfile-end 6 | */ 7 | 8 | #include 9 | @import Foundation; 10 | #import "CSSSelectorConverter.h" 11 | #import "CSSSelectorGrammar.h" 12 | #import "CPLALR1Parser.h" 13 | 14 | int main(int argc, const char * argv[]) 15 | { 16 | @autoreleasepool { 17 | if (argc >= 3) 18 | { 19 | NSString* grammaFile = [[NSString stringWithCString:argv[1] encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath]; 20 | NSString* outputFile = [[NSString stringWithCString:argv[2] encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath]; 21 | CSSSelectorGrammar* grammar = [[CSSSelectorGrammar alloc] initWithPath:grammaFile]; 22 | CPLALR1Parser* parser1 = [CPLALR1Parser parserWithGrammar:grammar]; 23 | [NSKeyedArchiver archiveRootObject:@{@"parser" : parser1} 24 | toFile:outputFile]; 25 | } 26 | else 27 | { 28 | NSLog(@"Usage: CSSSelectorParserGenerator "); 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /CSSSelectorConverter.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'CSSSelectorConverter' 3 | s.version = '1.2.3' 4 | s.license = 'MIT' 5 | s.summary = 'Objective-C/Cocoa String Tokenizer and Parser toolkit. Supports Grammars.' 6 | s.homepage = 'https://github.com/siuying/CSSSelectorConverter' 7 | s.author = { 'Francis Chong' => 'francis@ignition.hk' } 8 | 9 | s.source = { :git => 'https://github.com/siuying/CSSSelectorConverter.git', :tag => s.version.to_s } 10 | 11 | s.description = %{ 12 | A CSS Selector to XPath Selector for Objective-C. Support mostly used subset of CSS Selector Level 3. 13 | } 14 | 15 | s.ios.deployment_target = '6.0' 16 | s.osx.deployment_target = '10.8' 17 | 18 | s.dependency 'CocoaLumberjack', '~> 2.0.0' 19 | s.dependency 'NUIParse' 20 | s.requires_arc = true 21 | 22 | s.public_header_files = "CSSSelectorConverter/CSSSelectorConverter.h", "CSSSelectorConverter/CSSSelectorToXPathConverter.h" 23 | s.source_files = 'CSSSelectorConverter/CSS*.{m,h}' 24 | s.prefix_header_contents = "#import \"CSSSelectorConverter.h\"" 25 | s.requires_arc = true 26 | s.resources = ['CSSSelectorConverter/*.{txt}', 'CSSSelectorConverter/CSSSelectorParser.plist'] 27 | end 28 | -------------------------------------------------------------------------------- /CSSSelectorConverter/IGDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // IGDetailViewController.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "IGDetailViewController.h" 10 | 11 | @interface IGDetailViewController () 12 | - (void)configureView; 13 | @end 14 | 15 | @implementation IGDetailViewController 16 | 17 | #pragma mark - Managing the detail item 18 | 19 | - (void)setDetailItem:(id)newDetailItem 20 | { 21 | if (_detailItem != newDetailItem) { 22 | _detailItem = newDetailItem; 23 | 24 | // Update the view. 25 | [self configureView]; 26 | } 27 | } 28 | 29 | - (void)configureView 30 | { 31 | // Update the user interface for the detail item. 32 | 33 | if (self.detailItem) { 34 | self.detailDescriptionLabel.text = [self.detailItem description]; 35 | } 36 | } 37 | 38 | - (void)viewDidLoad 39 | { 40 | [super viewDidLoad]; 41 | // Do any additional setup after loading the view, typically from a nib. 42 | [self configureView]; 43 | } 44 | 45 | - (void)didReceiveMemoryWarning 46 | { 47 | [super didReceiveMemoryWarning]; 48 | // Dispose of any resources that can be recreated. 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CSSSelectorGroup.h" 3 | #import "NUIPParser.h" 4 | #import "NUIPTokeniser.h" 5 | 6 | extern NSString* const CSSSelectorParserException; 7 | extern NSString* const CSSSelectorParserErrorDomain; 8 | extern NSString* const CSSSelectorParserErrorInputStreamKey; 9 | extern NSString* const CSSSelectorParserErrorAcceptableTokenKey; 10 | 11 | @class CSSSelectorGroup; 12 | 13 | /** 14 | * CSSSelectorParser parse a CSS Selector and return a CSSSelectorGroup. 15 | * 16 | * Use ``CSSSelectorXPathVisitor`` to convert the returned tree into a XPath. 17 | * @see CSSSelectorParser 18 | */ 19 | @interface CSSSelectorParser : NSObject 20 | 21 | /** 22 | Last error encountered by the parser. 23 | */ 24 | @property (nonatomic, strong) NSError* lastError; 25 | 26 | -(instancetype) init; 27 | 28 | -(instancetype) initWithParser:(NUIPParser*)parser; 29 | 30 | /** 31 | * Parse a CSS Selector and return a CSSSelectorGroup object. 32 | * 33 | * 34 | * @param css The css selector 35 | * @param error If the parse failed and parser return nil, error is set to last known error. 36 | * @return CSSSelectorGroup the parsed selector. Or nil if error occurred. 37 | */ 38 | - (CSSSelectorGroup*)parse:(NSString *)css error:(NSError**)error; 39 | 40 | @end 41 | 42 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorToXPathConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSToXPathConverter.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | #import "CSSSelectorParser.h" 9 | #import "CSSSelectorToXPathConverter.h" 10 | #import "CSSBaseSelector.h" 11 | #import "CSSSelectorXPathVisitor.h" 12 | 13 | @implementation CSSSelectorToXPathConverter 14 | 15 | +(instancetype) sharedConverter 16 | { 17 | static dispatch_once_t onceToken; 18 | static CSSSelectorToXPathConverter* _converter; 19 | dispatch_once(&onceToken, ^{ 20 | _converter = [[self alloc] init]; 21 | }); 22 | return _converter; 23 | } 24 | 25 | -(id) initWithParser:(CSSSelectorParser*)parser { 26 | self = [super init]; 27 | self.parser = parser; 28 | return self; 29 | } 30 | 31 | -(id) init { 32 | return [self initWithParser:[[CSSSelectorParser alloc] init]]; 33 | } 34 | 35 | -(NSString*)xpathWithCSS:(NSString*)css error:(NSError*__autoreleasing*)error{ 36 | CSSSelectorGroup* group = [self.parser parse:css error:error]; 37 | if (group) { 38 | CSSSelectorXPathVisitor* visitor = [[CSSSelectorXPathVisitor alloc] init]; 39 | [visitor visit:group]; 40 | return [visitor xpathString]; 41 | } else { 42 | return nil; 43 | } 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/CSSSelectorParserSpec.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorGrammarSpec.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSSelectorParser.h" 11 | #import "NUIParse.h" 12 | #import "CSSSelectorGrammar.h" 13 | #import "CSSSelectorTokeniser.h" 14 | 15 | SPEC_BEGIN(CSSSelectorParserSpec) 16 | 17 | describe(@"CSSSelectorParser", ^{ 18 | context(@"serialization", ^{ 19 | xit(@"should serialize and deserialize a parser", ^{ 20 | CSSSelectorTokeniser* tokenizer1 = [[CSSSelectorTokeniser alloc] init]; 21 | CSSSelectorTokeniser* tokenizer2 = [[CSSSelectorTokeniser alloc] init]; 22 | 23 | NUIPLALR1Parser* parser1 = [NUIPLALR1Parser parserWithGrammar:[[CSSSelectorGrammar alloc] initWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"CSSSelectorGrammar" ofType:@"txt"]]]; 24 | NUIPSyntaxTree* result1 = [parser1 parse:[tokenizer1 tokenise:@"title .article"]]; 25 | 26 | NSData* data = [NSKeyedArchiver archivedDataWithRootObject:parser1]; 27 | NUIPLALR1Parser *parser2 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 28 | NUIPSyntaxTree* result2 = [parser2 parse:[tokenizer2 tokenise:@"title .article"]]; 29 | 30 | [[result1 should] equal:result2]; 31 | }); 32 | }); 33 | }); 34 | 35 | SPEC_END 36 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorGroup.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSSelectorGroup.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSSelectorGroup 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | self = [self init]; 16 | if (self) { 17 | CSSSelectors* selector = [syntaxTree valueForTag:@"firstSelector"]; 18 | if (selector) { 19 | [self addSelectors:selector]; 20 | } else { 21 | [NSException raise:NSInvalidArgumentException format:@"should at least contain one selector"]; 22 | } 23 | 24 | NSArray* subtree = [syntaxTree valueForTag:@"otherSelectors"]; 25 | NSArray* flattenSubtree = [subtree valueForKeyPath: @"@unionOfArrays.self"]; 26 | [flattenSubtree enumerateObjectsUsingBlock:^(CSSSelectors* other, NSUInteger idx, BOOL *stop) { 27 | if ([other isKindOfClass:[CSSSelectors class]]) { 28 | [self addSelectors:other]; 29 | } 30 | }]; 31 | } 32 | return self; 33 | } 34 | 35 | -(instancetype) init { 36 | self = [super init]; 37 | self.selectors = [[NSMutableArray alloc] init]; 38 | return self; 39 | } 40 | 41 | -(void) addSelectors:(CSSSelectors *)theSelectors { 42 | [self.selectors addObject:theSelectors]; 43 | } 44 | 45 | -(NSString*) description { 46 | return [NSString stringWithFormat:@"", [self.selectors componentsJoinedByString:@", "]]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorConverter-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | hk.ignition.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarTintParameters 34 | 35 | UINavigationBar 36 | 37 | Style 38 | UIBarStyleDefault 39 | Translucent 40 | 41 | 42 | 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorGrammar.txt: -------------------------------------------------------------------------------- 1 | CSSSelectorGroup ::= firstSelector@ otherSelectors@( )*; 2 | CSSSelectors ::= firstSequence@ otherSequences@( )*; 3 | CSSSelectorSequence ::= (universal@ | type@) selectorsWithType@( | | | )* | selectorsWithoutType@( | | | )+; 4 | CSSSelectorAttribute ::= '[' 'Whitespace'* attrName@'Identifier' (op@ attrValue@)? ']'; 5 | CSSSelectorAttributeOperator ::= | | ; 6 | CSSPseudoClass ::= ':' ':'? (className@'Identifier'); 7 | CSSCombinator ::= | | | 'Whitespace'+; 8 | CSSClassSelector ::= '.' className@'Identifier'; 9 | CSSIDSelector ::= '#' idName@'Identifier'; 10 | CSSTypeSelector ::= typeName@'Identifier'; 11 | CSSUniversalSelector ::= '*'; 12 | CSSPseudoExpression ::= (( '+' | '-' | 'Number' 'Identifier' | 'Number' | 'Identifier' ) 'Whitespace'* )+; 13 | QuotedString ::= 'String'; 14 | Dashmatch ::= '|='; 15 | Includes ::= '~='; 16 | Equal ::= '='; 17 | Comma ::= ','; 18 | Plus ::= '+'; 19 | Greater ::= '>'; 20 | Tilde ::= '~'; -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorGrammar.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorGrammar.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSSelectorGrammar.h" 10 | #import "CSSTypeSelector.h" 11 | #import "CSSUniversalSelector.h" 12 | 13 | #import "DDLog.h" 14 | #undef LOG_LEVEL_DEF 15 | #define LOG_LEVEL_DEF cssSelectorLogLevel 16 | static const int cssSelectorLogLevel = LOG_LEVEL_VERBOSE; 17 | 18 | @implementation CSSSelectorGrammar 19 | 20 | -(instancetype) init 21 | { 22 | NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:@"CSSSelectorGrammar" ofType:@"txt"]; 23 | return [self initWithPath:path]; 24 | } 25 | 26 | -(instancetype) initWithPath:(NSString*)path 27 | { 28 | NSError* error; 29 | NSString* grammar = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; 30 | if (!grammar) { 31 | if (error) { 32 | DDLogError(@"missing grammar file %@, error: %@", path, error); 33 | [NSException raise:NSInvalidArgumentException format:@"missing grammar file %@, error: %@", path, error]; 34 | } else { 35 | DDLogError(@"missing grammar file %@", path); 36 | [NSException raise:NSInvalidArgumentException format:@"missing grammar file %@", path]; 37 | } 38 | } 39 | self = [super initWithStart:@"CSSSelectorGroup" backusNaurForm:grammar error:&error]; 40 | if (!self) { 41 | if (error) { 42 | DDLogError(@"error compile language = %@", error); 43 | } 44 | } 45 | return self; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectors.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectors.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | #import "NUIParse.h" 9 | #import "CSSSelectors.h" 10 | #import "CSSCombinator.h" 11 | #import "CSSSelectorSequence.h" 12 | 13 | @implementation CSSSelectors 14 | 15 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 16 | self = [self init]; 17 | if (self) { 18 | CSSSelectorSequence* seq = [syntaxTree valueForTag:@"firstSequence"]; 19 | if (seq) { 20 | [self addSelector:seq]; 21 | } 22 | 23 | NSArray* otherSequences = [syntaxTree valueForTag:@"otherSequences"]; 24 | [otherSequences enumerateObjectsUsingBlock:^(NSArray* sequence, NSUInteger idx, BOOL *stop) { 25 | [sequence enumerateObjectsUsingBlock:^(CSSBaseSelector* selector, NSUInteger idx, BOOL *stop) { 26 | [self addSelector:selector]; 27 | }]; 28 | }]; 29 | } 30 | return self; 31 | } 32 | 33 | -(instancetype) init { 34 | self = [super init]; 35 | self.selectors = [[NSMutableArray alloc] init]; 36 | return self; 37 | } 38 | 39 | -(void) addSelector:(CSSBaseSelector*)selector { 40 | if (![selector isKindOfClass:[CSSSelectorSequence class]] && ![selector isKindOfClass:[CSSCombinator class]]) { 41 | [NSException raise:NSInvalidArgumentException format:@"Only allowed to add selector of type CSSSelectorSequence or CSSCombinator, given: %@", [selector class]]; 42 | } 43 | 44 | [self.selectors addObject:selector]; 45 | } 46 | 47 | -(NSString*) description { 48 | return [NSString stringWithFormat:@"", self.selectors]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CSSSelectorConverter.xcworkspace/xcshareddata/CSSSelectorConverter.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "122DB07625ACCDABC9818C06D3A839B56B29D4FD", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "20B5E220B44D3958A2219B13999BCD96DC9444FE" : 0, 8 | "122DB07625ACCDABC9818C06D3A839B56B29D4FD" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F3C80365-7344-4DF4-8217-F1266652B9AD", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "20B5E220B44D3958A2219B13999BCD96DC9444FE" : "CSSSelectorConverter\/vendor\/CoreParse", 13 | "122DB07625ACCDABC9818C06D3A839B56B29D4FD" : "CSSSelectorConverter" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "CSSSelectorConverter", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CSSSelectorConverter.xcworkspace", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/github.com\/siuying\/CSSSelectorConverter.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "122DB07625ACCDABC9818C06D3A839B56B29D4FD" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/beelsebob\/CoreParse.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "20B5E220B44D3958A2219B13999BCD96DC9444FE" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorAttributeOperator.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorAttributeType.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | #import "DDLog.h" 9 | #undef LOG_LEVEL_DEF 10 | #define LOG_LEVEL_DEF cssSelectorLogLevel 11 | static const int cssSelectorLogLevel = LOG_LEVEL_VERBOSE; 12 | #import "NUIParse.h" 13 | 14 | #import "CSSSelectorAttributeOperator.h" 15 | 16 | @implementation CSSSelectorAttributeOperator 17 | 18 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 19 | self = [self init]; 20 | if (self) { 21 | NSArray *components = [syntaxTree children]; 22 | if ([components count] == 1) { 23 | NUIPKeywordToken* token = [components[0] children][0]; 24 | if ([token isKeywordToken]) { 25 | self.name = [token keyword]; 26 | self.attributeOperator = [[self class] operatorWithString:[token keyword]]; 27 | } 28 | } 29 | } 30 | return self; 31 | } 32 | 33 | +(instancetype) selectorWithName:(NSString*)name { 34 | CSSSelectorAttributeOperator* attrType = [[self alloc] init]; 35 | attrType.name = name; 36 | attrType.attributeOperator = [self operatorWithString:name]; 37 | return attrType; 38 | } 39 | 40 | -(NSString*) description { 41 | return [NSString stringWithFormat:@"", self.name]; 42 | } 43 | 44 | +(CSSSelectorAttributeOperatorType) operatorWithString:(NSString*) type { 45 | if ([type isEqualToString:@"="]) { 46 | return CSSSelectorAttributeOperatorTypeEqual; 47 | } else if ([type isEqualToString:@"~="]) { 48 | return CSSSelectorAttributeOperatorTypeIncludes; 49 | } else if ([type isEqualToString:@"|="]) { 50 | return CSSSelectorAttributeOperatorTypeDash; 51 | } 52 | 53 | DDLogError(@"operator must be =, ~= or |=, given: %@", type); 54 | [NSException raise:NSInvalidArgumentException format:@"operator must be =, ~= or |=, given: %@", type]; 55 | return CSSSelectorAttributeOperatorTypeNone; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /CSSSelectorConverter/IGAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // IGAppDelegate.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "IGAppDelegate.h" 10 | 11 | @implementation IGAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | return YES; 16 | } 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application 19 | { 20 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 21 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 22 | } 23 | 24 | - (void)applicationDidEnterBackground:(UIApplication *)application 25 | { 26 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 28 | } 29 | 30 | - (void)applicationWillEnterForeground:(UIApplication *)application 31 | { 32 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 33 | } 34 | 35 | - (void)applicationDidBecomeActive:(UIApplication *)application 36 | { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | - (void)applicationWillTerminate:(UIApplication *)application 41 | { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CSSSelectorConverter.xcworkspace/xcshareddata/CSSSelectorConverter.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | F3C80365-7344-4DF4-8217-F1266652B9AD 9 | IDESourceControlProjectName 10 | CSSSelectorConverter 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 122DB07625ACCDABC9818C06D3A839B56B29D4FD 14 | ssh://github.com/siuying/CSSSelectorConverter.git 15 | 20B5E220B44D3958A2219B13999BCD96DC9444FE 16 | https://github.com/beelsebob/CoreParse.git 17 | 18 | IDESourceControlProjectPath 19 | CSSSelectorConverter.xcworkspace 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 122DB07625ACCDABC9818C06D3A839B56B29D4FD 23 | .. 24 | 20B5E220B44D3958A2219B13999BCD96DC9444FE 25 | ../vendor/CoreParse 26 | 27 | IDESourceControlProjectURL 28 | ssh://github.com/siuying/CSSSelectorConverter.git 29 | IDESourceControlProjectVersion 30 | 111 31 | IDESourceControlProjectWCCIdentifier 32 | 122DB07625ACCDABC9818C06D3A839B56B29D4FD 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | 20B5E220B44D3958A2219B13999BCD96DC9444FE 40 | IDESourceControlWCCName 41 | CoreParse 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 122DB07625ACCDABC9818C06D3A839B56B29D4FD 48 | IDESourceControlWCCName 49 | CSSSelectorConverter 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS Selector Converter 2 | 3 | A CSS Selector to XPath Selector for Objective-C. Support mostly used subset of [CSS Selector Level 3](http://www.w3.org/TR/css3-selectors/). 4 | 5 | I build this converter so that I can use `.class` instead of `//*[contains(concat(' ', normalize-space(@class), ' '), ' class ')]` in [IGHTMLQuery](https://github.com/siuying/IGHTMLQuery/). 6 | 7 | ## Usage 8 | 9 | ```objective-c 10 | #import "CSSSelectorConverter.h" 11 | 12 | CSSSelectorToXPathConverter* converter = [[CSSSelectorToXPathConverter alloc] init]; 13 | [converter xpathWithCSS:@"p" error:nil]; 14 | // => "//p" 15 | 16 | [converter xpathWithCSS:@"p.intro" error:nil]; 17 | // => "//p[contains(concat(' ', normalize-space(@class), ' '), ' intro ')]" 18 | ``` 19 | 20 | ## Status 21 | 22 | It supports following CSS Selectors: 23 | 24 | ``` 25 | * "//*" 26 | p "//p" 27 | p.intro "//p[contains(concat(' ', normalize-space(@class), ' '), ' intro ')]" 28 | p#apple "//p[@id = 'apple']" 29 | p * "//p//*" 30 | p > * "//p/*" 31 | H1 + P "//H1/following-sibling::*[1]/self::P" 32 | H1 ~ P "//H1/following-sibling::P" 33 | ul, ol "//ul | //ol" 34 | p[align] "//p[@align]" 35 | p[class~="intro"] "//p[contains(concat(\" \", @class, \" \"),concat(\" \", 'intro', \" \"))]" 36 | div[att|="val"] "//div[@att = \"val\" or starts-with(@att, concat(\"val\", '-'))]" 37 | ``` 38 | 39 | It supports following pseduo classes: 40 | 41 | - first-child 42 | - last-child 43 | - first-of-type 44 | - last-of-type 45 | - only-child 46 | - only-of-type 47 | - empty 48 | 49 | Currently pseduo classes with parameters are not supported (I probably will not implement them until I really NEEDS them): 50 | 51 | - nth-child() 52 | - nth-last-child() 53 | - nth-of-type() 54 | - nth-last-of-type() 55 | - not() 56 | 57 | Following pseduo classes will not be supported: 58 | 59 | - Dynamic pseudo classes (:link, :visied, :hover ... etc) 60 | - UI elements states pseudo-classes (:enabled, :checked, :indeterminate) 61 | - :target 62 | - :lang 63 | - :root 64 | 65 | ## Development 66 | 67 | ### Building the project 68 | 69 | 1. Install cocoapods 70 | 2. Install pods: ``pod install`` 71 | 72 | ## License 73 | 74 | MIT License. See License.txt. -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorSequence.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorSequence.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "DDLog.h" 10 | #import "NUIParse.h" 11 | 12 | #undef LOG_LEVEL_DEF 13 | #define LOG_LEVEL_DEF cssSelectorLogLevel 14 | static const int cssSelectorLogLevel = LOG_LEVEL_VERBOSE; 15 | 16 | #import "CSSSelectorSequence.h" 17 | #import "CSSUniversalSelector.h" 18 | #import "CSSNamedSelector.h" 19 | #import "CSSTypeSelector.h" 20 | #import "CSSIDSelector.h" 21 | #import "CSSClassSelector.h" 22 | #import "CSSSelectorAttribute.h" 23 | #import "CSSPseudoClass.h" 24 | #import "CSSCombinator.h" 25 | 26 | @implementation CSSSelectorSequence 27 | 28 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 29 | self = [self init]; 30 | if (self) { 31 | NSArray* selectors = nil; 32 | if ([syntaxTree valueForTag:@"universal"]) { 33 | self.universalOrTypeSelector = [syntaxTree valueForTag:@"universal"]; 34 | NSArray* subtree = [syntaxTree valueForTag:@"selectorsWithType"]; 35 | selectors = [subtree valueForKeyPath:@"@unionOfArrays.self"]; 36 | 37 | } else if ([syntaxTree valueForTag:@"type"]) { 38 | self.universalOrTypeSelector = [syntaxTree valueForTag:@"type"]; 39 | NSArray* subtree = [syntaxTree valueForTag:@"selectorsWithType"]; 40 | selectors = [subtree valueForKeyPath:@"@unionOfArrays.self"]; 41 | 42 | } else { 43 | NSArray* subtree = [syntaxTree valueForTag:@"selectorsWithoutType"]; 44 | selectors = [subtree valueForKeyPath:@"@unionOfArrays.self"]; 45 | 46 | } 47 | 48 | if (selectors && [selectors isKindOfClass:[NSArray class]]) { 49 | [selectors enumerateObjectsUsingBlock:^(CSSBaseSelector* selector, NSUInteger idx, BOOL *stop) { 50 | [self addSelector:selector]; 51 | }]; 52 | } else { 53 | [NSException raise:NSInvalidArgumentException format:@"expected NSArray, receive: %@", syntaxTree]; 54 | } 55 | } 56 | return self; 57 | } 58 | 59 | -(instancetype) init { 60 | self = [super init]; 61 | self.universalOrTypeSelector = nil; 62 | self.otherSelectors = [[NSMutableArray alloc] init]; 63 | return self; 64 | } 65 | 66 | -(NSString*) description { 67 | return [NSString stringWithFormat:@"", self.universalOrTypeSelector, [self.otherSelectors componentsJoinedByString:@" "]]; 68 | } 69 | 70 | -(void) addSelector:(CSSBaseSelector*)selector { 71 | if ([selector isKindOfClass:[CSSIDSelector class]] || 72 | [selector isKindOfClass:[CSSClassSelector class]] || 73 | [selector isKindOfClass:[CSSSelectorAttribute class]]) { 74 | [self.otherSelectors addObject:selector]; 75 | 76 | } else if ([selector isKindOfClass:[CSSPseudoClass class]]) { 77 | self.pseudoClass = (CSSPseudoClass*) selector; 78 | 79 | } else { 80 | DDLogError(@"attempt to add unknown selector to sequence: %@", selector); 81 | [NSException raise:NSInternalInconsistencyException format:@"attempt to add unknown selector to sequence: %@", selector]; 82 | } 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSCombinator.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSCombinator.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Chong Francis on 14年1月8日. 6 | // Copyright (c) 2014年 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSCombinator.h" 10 | #import "NUIParse.h" 11 | 12 | @implementation CSSCombinator 13 | 14 | - (id)initWithSyntaxTree:(NUIPSyntaxTree *)syntaxTree { 15 | self = [self init]; 16 | NSArray *components = [syntaxTree children]; 17 | if ([components count] >= 1) { 18 | id component = components[0]; 19 | if ([component isWhiteSpaceToken]) { 20 | self.type = CSSCombinatorTypeNone; 21 | } else if ([component isSyntaxTree]) { 22 | id token = [component children][0]; 23 | if ([token isKeywordToken]) { 24 | NSString* keyword = [token keyword]; 25 | if ([keyword isEqualToString:@">"]) { 26 | self.type = CSSCombinatorTypeDescendant; 27 | } else if ([keyword isEqualToString:@"+"]) { 28 | self.type = CSSCombinatorTypeAdjacent; 29 | } else if ([keyword isEqualToString:@"~"]) { 30 | self.type = CSSCombinatorTypeGeneralSibling; 31 | } else { 32 | [NSException raise:NSInvalidArgumentException format:@"Unexpected keyword: %@", keyword]; 33 | } 34 | } else { 35 | [NSException raise:NSInvalidArgumentException format:@"Unexpected token, not a keyword: %@", token]; 36 | } 37 | } else if ([component isKeywordToken]) { 38 | NSString* keyword = [component keyword]; 39 | if ([keyword isEqualToString:@">"]) { 40 | self.type = CSSCombinatorTypeDescendant; 41 | } else if ([keyword isEqualToString:@"+"]) { 42 | self.type = CSSCombinatorTypeAdjacent; 43 | } else if ([keyword isEqualToString:@"~"]) { 44 | self.type = CSSCombinatorTypeGeneralSibling; 45 | } else { 46 | [NSException raise:NSInvalidArgumentException format:@"Unexpected keyword: %@", keyword]; 47 | } 48 | } 49 | 50 | } 51 | return self; 52 | } 53 | 54 | +(CSSCombinator*) noneCombinator { 55 | CSSCombinator* combinator = [[CSSCombinator alloc] init]; 56 | combinator.type = CSSCombinatorTypeNone; 57 | return combinator; 58 | } 59 | 60 | +(NSArray*) combinatorStrings { 61 | static dispatch_once_t onceToken; 62 | static NSArray* _combinatorStrings; 63 | dispatch_once(&onceToken, ^{ 64 | _combinatorStrings = @[@">", @"+", @"~"]; 65 | }); 66 | return _combinatorStrings; 67 | } 68 | 69 | -(NSString*) description { 70 | return [NSString stringWithFormat:@"", self.typeString]; 71 | } 72 | 73 | -(NSString*) typeString { 74 | switch (self.type) { 75 | case CSSCombinatorTypeNone: 76 | { 77 | return @"(none)"; 78 | } 79 | break; 80 | case CSSCombinatorTypeDescendant: 81 | { 82 | return @">"; 83 | } 84 | case CSSCombinatorTypeAdjacent: 85 | { 86 | return @"+"; 87 | } 88 | case CSSCombinatorTypeGeneralSibling: 89 | { 90 | return @"~"; 91 | } 92 | } 93 | return nil; 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorParser.m: -------------------------------------------------------------------------------- 1 | #import "CSSSelectorParser.h" 2 | #import "CSSSelectorGrammar.h" 3 | #import "CSSSelectorTokeniser.h" 4 | #import "NUIParse.h" 5 | #import "DDLog.h" 6 | 7 | #undef LOG_LEVEL_DEF 8 | #define LOG_LEVEL_DEF cssSelectorLogLevel 9 | static const int cssSelectorLogLevel = LOG_LEVEL_ERROR; 10 | 11 | NSString* const CSSSelectorParserException = @"CSSSelectorParserException"; 12 | NSString* const CSSSelectorParserErrorDomain = @"CSSSelectorParserErrorDomain"; 13 | NSString* const CSSSelectorParserErrorInputStreamKey = @"input stream"; 14 | NSString* const CSSSelectorParserErrorAcceptableTokenKey = @"acceptable token"; 15 | 16 | enum { 17 | CSSSelectorParserRuleQuotedString = 1 18 | }; 19 | 20 | @interface CSSSelectorParser () 21 | @property (nonatomic, strong) CSSSelectorTokeniser *tokeniser; 22 | @property (nonatomic, strong) NUIPParser* parser; 23 | @end 24 | 25 | @implementation CSSSelectorParser 26 | 27 | - (id)init { 28 | NUIPLALR1Parser* parser = [NUIPLALR1Parser parserWithGrammar:[[CSSSelectorGrammar alloc] initWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"CSSSelectorGrammar" ofType:@"txt"]]]; 29 | return [self initWithParser:parser]; 30 | } 31 | 32 | -(instancetype) initWithParser:(NUIPParser*)parser 33 | { 34 | self = [super init]; 35 | self.tokeniser = [[CSSSelectorTokeniser alloc] init]; 36 | self.tokeniser.delegate = self; 37 | self.parser = parser; 38 | self.parser.delegate = self; 39 | return self; 40 | } 41 | 42 | - (CSSSelectorGroup*)parse:(NSString *)css error:(NSError*__autoreleasing*)error 43 | { 44 | NUIPTokenStream *tokenStream = [self.tokeniser tokenise:css]; 45 | CSSSelectorGroup* result = [self.parser parse:tokenStream]; 46 | if (!result) { 47 | if (error) { 48 | *error = self.lastError; 49 | } else { 50 | DDLogError(@"CSSSelectorParser: parse error: %@", self.lastError); 51 | } 52 | } 53 | return result; 54 | } 55 | 56 | #pragma mark - CPParserDelegate 57 | 58 | - (id)parser:(NUIPParser *)parser didProduceSyntaxTree:(NUIPSyntaxTree *)syntaxTree 59 | { 60 | switch ([[syntaxTree rule] tag]) { 61 | case CSSSelectorParserRuleQuotedString: { 62 | NSArray* children = [syntaxTree children]; 63 | if ([children count] == 1 && [children[0] isQuotedToken]) { 64 | return [children[0] content]; 65 | } else { 66 | [NSException raise:CSSSelectorParserException 67 | format:@"unexpected token: should be a quoted token, now: %@", syntaxTree]; 68 | } 69 | } 70 | break; 71 | 72 | default: 73 | break; 74 | } 75 | return syntaxTree; 76 | } 77 | 78 | - (NUIPRecoveryAction *)parser:(NUIPParser *)parser didEncounterErrorOnInput:(NUIPTokenStream *)inputStream expecting:(NSSet *)acceptableTokens 79 | { 80 | NSError* error = [NSError errorWithDomain:CSSSelectorParserErrorDomain 81 | code:1 82 | userInfo:@{CSSSelectorParserErrorInputStreamKey: inputStream, CSSSelectorParserErrorAcceptableTokenKey: acceptableTokens}]; 83 | self.lastError = error; 84 | return [NUIPRecoveryAction recoveryActionStop]; 85 | } 86 | 87 | #pragma mark - CPTokeniserDelegate 88 | 89 | - (BOOL)tokeniser:(NUIPTokeniser *)tokeniser shouldConsumeToken:(NUIPToken *)token 90 | { 91 | return YES; 92 | } 93 | 94 | @end -------------------------------------------------------------------------------- /CSSSelectorConverter/IGMasterViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // IGMasterViewController.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "IGMasterViewController.h" 10 | 11 | #import "IGDetailViewController.h" 12 | 13 | @interface IGMasterViewController () { 14 | NSMutableArray *_objects; 15 | } 16 | @end 17 | 18 | @implementation IGMasterViewController 19 | 20 | - (void)awakeFromNib 21 | { 22 | [super awakeFromNib]; 23 | } 24 | 25 | - (void)viewDidLoad 26 | { 27 | [super viewDidLoad]; 28 | // Do any additional setup after loading the view, typically from a nib. 29 | self.navigationItem.leftBarButtonItem = self.editButtonItem; 30 | 31 | UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; 32 | self.navigationItem.rightBarButtonItem = addButton; 33 | } 34 | 35 | - (void)didReceiveMemoryWarning 36 | { 37 | [super didReceiveMemoryWarning]; 38 | // Dispose of any resources that can be recreated. 39 | } 40 | 41 | - (void)insertNewObject:(id)sender 42 | { 43 | if (!_objects) { 44 | _objects = [[NSMutableArray alloc] init]; 45 | } 46 | [_objects insertObject:[NSDate date] atIndex:0]; 47 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; 48 | [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 49 | } 50 | 51 | #pragma mark - Table View 52 | 53 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 54 | { 55 | return 1; 56 | } 57 | 58 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 59 | { 60 | return _objects.count; 61 | } 62 | 63 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 64 | { 65 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 66 | 67 | NSDate *object = _objects[indexPath.row]; 68 | cell.textLabel.text = [object description]; 69 | return cell; 70 | } 71 | 72 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath 73 | { 74 | // Return NO if you do not want the specified item to be editable. 75 | return YES; 76 | } 77 | 78 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 79 | { 80 | if (editingStyle == UITableViewCellEditingStyleDelete) { 81 | [_objects removeObjectAtIndex:indexPath.row]; 82 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 83 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 84 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. 85 | } 86 | } 87 | 88 | /* 89 | // Override to support rearranging the table view. 90 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 91 | { 92 | } 93 | */ 94 | 95 | /* 96 | // Override to support conditional rearranging of the table view. 97 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath 98 | { 99 | // Return NO if you do not want the item to be re-orderable. 100 | return YES; 101 | } 102 | */ 103 | 104 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 105 | { 106 | if ([[segue identifier] isEqualToString:@"showDetail"]) { 107 | NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; 108 | NSDate *object = _objects[indexPath.row]; 109 | [[segue destinationViewController] setDetailItem:object]; 110 | } 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CSSSelectorConverter.xcodeproj/xcshareddata/xcschemes/CSSSelectorConverter.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorTokeniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorTokeniser.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSSelectorTokeniser.h" 10 | #import "NUIPNumberRecogniser.h" 11 | #import "NUIPWhiteSpaceRecogniser.h" 12 | #import "NUIPQuotedRecogniser.h" 13 | #import "NUIPKeywordRecogniser.h" 14 | #import "NUIPIdentifierRecogniser.h" 15 | #import "NUIPRegexpRecogniser.h" 16 | 17 | @implementation CSSSelectorTokeniser 18 | 19 | -(id) init { 20 | self = [super init]; 21 | 22 | [self addTokenRecogniser:[NUIPIdentifierRecogniser identifierRecogniser]]; 23 | [self addTokenRecogniser:[NUIPNumberRecogniser numberRecogniser]]; 24 | [self addTokenRecogniser:[NUIPQuotedRecogniser quotedRecogniserWithStartQuote:@"\"" 25 | endQuote:@"\"" 26 | name:@"String"]]; 27 | [self addTokenRecogniser:[NUIPQuotedRecogniser quotedRecogniserWithStartQuote:@"\'" 28 | endQuote:@"\'" 29 | name:@"String"]]; 30 | 31 | NUIPRegexpKeywordRecogniserMatchHandler trimSpaceHandler = ^(NSString* tokenString, NSTextCheckingResult* match){ 32 | NSString* matched = [tokenString substringWithRange:match.range]; 33 | return [NUIPKeywordToken tokenWithKeyword:[matched stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; 34 | }; 35 | 36 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\~\\=)[ \t\r\n\f]*" options:0 error:nil] 37 | matchHandler:trimSpaceHandler]]; 38 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\|\\=)[ \t\r\n\f]*" options:0 error:nil] 39 | matchHandler:trimSpaceHandler]]; 40 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\=)[ \t\r\n\f]*" options:0 error:nil] 41 | matchHandler:trimSpaceHandler]]; 42 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\~)[ \t\r\n\f]*" options:0 error:nil] 43 | matchHandler:trimSpaceHandler]]; 44 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\+)[ \t\r\n\f]*" options:0 error:nil] 45 | matchHandler:trimSpaceHandler]]; 46 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\>)[ \t\r\n\f]*" options:0 error:nil] 47 | matchHandler:trimSpaceHandler]]; 48 | [self addTokenRecogniser:[NUIPRegexpRecogniser recogniserForRegexp:[NSRegularExpression regularExpressionWithPattern:@"[ \t\r\n\f]*(\\,)[ \t\r\n\f]*" options:0 error:nil] 49 | matchHandler:trimSpaceHandler]]; 50 | 51 | [self addTokenRecogniser:[NUIPWhiteSpaceRecogniser whiteSpaceRecogniser]]; 52 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@":"]]; 53 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"."]]; 54 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"#"]]; 55 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"-"]]; 56 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"("]]; 57 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@")"]]; 58 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"["]]; 59 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"]"]]; 60 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"*"]]; 61 | [self addTokenRecogniser:[NUIPKeywordRecogniser recogniserForKeyword:@"@"]]; 62 | 63 | return self; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/CSSToXPathConverterSpec.m: -------------------------------------------------------------------------------- 1 | // 2 | // NewKiwiSpec.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 7/1/14. 6 | // Copyright 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "Kiwi.h" 10 | #import "DDLog.h" 11 | #import "DDTTYLogger.h" 12 | #import "CSSSelectorConverter.h" 13 | #import "NUIParse.h" 14 | 15 | SPEC_BEGIN(CSSToXPathConverterSpec) 16 | __block CSSSelectorToXPathConverter *converter; 17 | 18 | describe(@"CSSToXPathParser", ^{ 19 | beforeAll(^{ 20 | DDTTYLogger* ttyLogger = [DDTTYLogger sharedInstance]; 21 | [DDLog addLogger:ttyLogger]; 22 | }); 23 | 24 | afterAll(^{ 25 | [DDLog flushLog]; 26 | }); 27 | 28 | beforeEach(^{ 29 | converter = [[CSSSelectorToXPathConverter alloc] init]; 30 | }); 31 | 32 | it(@"should parse universal selector", ^{ 33 | NSString* css = [converter xpathWithCSS:@"*" error:nil]; 34 | [[css should] equal:@"//*"]; 35 | }); 36 | 37 | it(@"should parse type selector", ^{ 38 | NSString* css = [converter xpathWithCSS:@"p" error:nil]; 39 | [[css should] equal:@"//p"]; 40 | }); 41 | 42 | it(@"should parse multiple type selector", ^{ 43 | NSString* css = [converter xpathWithCSS:@"h3 strong a, #fbPhotoPageAuthorName, title" error:nil]; 44 | [[css should] equal:@"//h3//strong//a | //*[@id = 'fbPhotoPageAuthorName'] | //title"]; 45 | }); 46 | 47 | it(@"should parse id selector", ^{ 48 | NSString* css = [converter xpathWithCSS:@"#header" error:nil]; 49 | [[css should] equal:@"//*[@id = 'header']"]; 50 | }); 51 | 52 | it(@"should parse class selector", ^{ 53 | NSString* css = [converter xpathWithCSS:@".header" error:nil]; 54 | [[css should] equal:@"//*[contains(concat(' ', normalize-space(@class), ' '), ' header ')]"]; 55 | }); 56 | 57 | it(@"should parse type with mixed class and id selector", ^{ 58 | NSString* css = [converter xpathWithCSS:@"p#header.red" error:nil]; 59 | [[css should] equal:@"//p[@id = 'header' and contains(concat(' ', normalize-space(@class), ' '), ' red ')]"]; 60 | }); 61 | 62 | it(@"should parse simple selector sequence", ^{ 63 | NSString* css = [converter xpathWithCSS:@"div p" error:nil]; 64 | [[css should] equal:@"//div//p"]; 65 | 66 | css = [converter xpathWithCSS:@"div *" error:nil]; 67 | [[css should] equal:@"//div//*"]; 68 | 69 | css = [converter xpathWithCSS:@"div#main p" error:nil]; 70 | [[css should] equal:@"//div[@id = 'main']//p"]; 71 | }); 72 | 73 | it(@"should parse descendant selector sequence", ^{ 74 | NSString* descendantCss = [converter xpathWithCSS:@"div#main p > a" error:nil]; 75 | [[descendantCss should] equal:@"//div[@id = 'main']//p/a"]; 76 | 77 | descendantCss = [converter xpathWithCSS:@"div#main p > a p > div" error:nil]; 78 | [[descendantCss shouldNot] beNil]; 79 | [[descendantCss should] equal:@"//div[@id = 'main']//p/a//p/div"]; 80 | }); 81 | 82 | it(@"should parse adjacent selector sequence", ^{ 83 | NSString* adjacentCss = [converter xpathWithCSS:@"h1 ~ p" error:nil]; 84 | [[adjacentCss should] equal:@"//h1/following-sibling::p"]; 85 | }); 86 | 87 | it(@"should parse selector group", ^{ 88 | NSString* css = [converter xpathWithCSS:@"div, p" error:nil]; 89 | [[css should] equal:@"//div | //p"]; 90 | }); 91 | 92 | it(@"should parse attribute", ^{ 93 | NSString* css = [converter xpathWithCSS:@"div[foo]" error:nil]; 94 | [[css should] equal:@"//div[@foo]"]; 95 | 96 | NSString* cssWithValue = [converter xpathWithCSS:@"div[width=\"100\"]" error:nil]; 97 | [[cssWithValue should] equal:@"//div[@width = \"100\"]"]; 98 | 99 | NSString* cssWithIncludesValue = [converter xpathWithCSS:@"div[class~=\"100\"]" error:nil]; 100 | [[cssWithIncludesValue should] equal:@"//div[contains(concat(\" \", @class, \" \"),concat(\" \", \"100\", \" \"))]"]; 101 | 102 | NSString* cssWithDashValue = [converter xpathWithCSS:@"div[att|=\"val\"]" error:nil]; 103 | [[cssWithDashValue should] equal:@"//div[@att = \"val\" or starts-with(@att, concat(\"val\", '-'))]"]; 104 | }); 105 | 106 | it(@"should parse pseudo class", ^{ 107 | NSString* firstChild = [converter xpathWithCSS:@"div > p:first-child" error:nil]; 108 | [[firstChild should] equal:@"//div/*[position() = 1 and self::p]"]; 109 | 110 | NSString* lastChild = [converter xpathWithCSS:@"ol > li:last-child" error:nil]; 111 | [[lastChild should] equal:@"//ol/*[position() = last() and self::li]"]; 112 | 113 | NSString* firstOfType = [converter xpathWithCSS:@"dl dt:first-of-type" error:nil]; 114 | [[firstOfType should] equal:@"//dl//dt[position() = 1]"]; 115 | 116 | NSString* lastOfType = [converter xpathWithCSS:@"tr > td:last-of-type" error:nil]; 117 | [[lastOfType should] equal:@"//tr/td[position() = last()]"]; 118 | 119 | NSString* onlyChild = [converter xpathWithCSS:@"p:only-child" error:nil]; 120 | [[onlyChild should] equal:@"//*[last() = 1 and self::p]"]; 121 | 122 | NSString* onlyOfType = [converter xpathWithCSS:@"p:only-of-type" error:nil]; 123 | [[onlyOfType should] equal:@"//p[last() = 1]"]; 124 | 125 | NSString* empty = [converter xpathWithCSS:@"div:empty" error:nil]; 126 | [[empty should] equal:@"//div[not(node())]"]; 127 | }); 128 | 129 | // disabled until we properly implement pseudo class with params 130 | // it(@"should parse function pseudo class nth-child()", ^{ 131 | // NSError *error = nil; 132 | // NSString* nthChild = [converter xpathWithCSS:@"tr:nth-child(2n+1)" error:&error]; 133 | // [[nthChild should] equal:@"//tr[(position() >= 1) and (((position()-1) mod 2) = 0)]"]; 134 | // 135 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(2n+0)" error:&error]; 136 | // [[nthChild should] equal:@"//tr[(position() mod 2) = 0]"]; 137 | // 138 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(odd)" error:&error]; 139 | // [[nthChild should] equal:@"//tr[(position() >= 1) and (((position()-1) mod 2) = 0)]"]; 140 | // 141 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(even)" error:&error]; 142 | // [[nthChild should] equal:@"//tr[(position() mod 2) = 0]"]; 143 | // 144 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(odd)" error:&error]; 145 | // [[nthChild should] equal:@"//tr[(position() >= 1) and (((position()-1) mod 2) = 0)]"]; 146 | // 147 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(10n+9)" error:&error]; 148 | // [[nthChild should] equal:@"//tr[(position() >= 9) and (((position()-9) mod 10) = 0)]"]; 149 | // 150 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(10n-1)" error:&error]; 151 | // [[nthChild should] equal:@"//tr[(position() >= 9) and (((position()-9) mod 10) = 0)]"]; 152 | // 153 | // nthChild = [converter xpathWithCSS:@"tr:nth-child(n-2)" error:&error]; 154 | // [[nthChild should] equal:@"//*[position() = n-2 and self::tr]"]; 155 | // }); 156 | // 157 | // it(@"should parse function pseudo class nth-last-child()", ^{ 158 | // NSError *error = nil; 159 | // NSString* nthChild = [converter xpathWithCSS:@"tr:nth-last-child(n-2)" error:&error]; 160 | // [[nthChild should] equal:@"//tr[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]"]; 161 | // }); 162 | }); 163 | 164 | SPEC_END 165 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/CSSSelectorXPathVisitorSpec.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorXPathVisitorSpec.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSSelectorXPathVisitor.h" 11 | #import "CSSSelectorGroup.h" 12 | #import "CSSUniversalSelector.h" 13 | #import "CSSIDSelector.h" 14 | #import "CSSTypeSelector.h" 15 | #import "CSSClassSelector.h" 16 | #import "CSSSelectorSequence.h" 17 | #import "CSSSelectors.h" 18 | #import "CSSCombinator.h" 19 | #import "CSSSelectorAttribute.h" 20 | #import "CSSSelectorAttributeOperator.h" 21 | #import "NUIParse.h" 22 | 23 | SPEC_BEGIN(CSSSelectorXPathVisitorSpec) 24 | 25 | describe(@"CSSSelectorXPathVisitor", ^{ 26 | __block CSSSelectorXPathVisitor* visitor; 27 | 28 | beforeEach(^{ 29 | visitor = [[CSSSelectorXPathVisitor alloc] init]; 30 | }); 31 | 32 | it(@"render xpath for CSSUniversalSelector", ^{ 33 | CSSUniversalSelector* selector = [[CSSUniversalSelector alloc] init]; 34 | [visitor visit:selector]; 35 | NSString* xpath = [visitor xpathString]; 36 | [[xpath should] equal:@"*"]; 37 | }); 38 | 39 | it(@"render xpath for CSSTypeSelector", ^{ 40 | CSSTypeSelector* selector = [[CSSTypeSelector alloc] init]; 41 | selector.name = @"table"; 42 | [visitor visit:selector]; 43 | NSString* xpath = [visitor xpathString]; 44 | [[xpath should] equal:@"table"]; 45 | }); 46 | 47 | it(@"render xpath for CSSIDSelector", ^{ 48 | CSSIDSelector* selector = [[CSSIDSelector alloc] init]; 49 | selector.name = @"p"; 50 | [visitor visit:selector]; 51 | NSString* xpath = [visitor xpathString]; 52 | [[xpath should] equal:@"@id = 'p'"]; 53 | }); 54 | 55 | it(@"render xpath for CSSClassSelector", ^{ 56 | CSSClassSelector* selector = [[CSSClassSelector alloc] init]; 57 | selector.name = @"red"; 58 | [visitor visit:selector]; 59 | NSString* xpath = [visitor xpathString]; 60 | [[xpath should] equal:@"contains(concat(' ', normalize-space(@class), ' '), ' red ')"]; 61 | }); 62 | 63 | it(@"render xpath for CSSSelectorSequence", ^{ 64 | CSSClassSelector* classSelector = [[CSSClassSelector alloc] init]; 65 | classSelector.name = @"red"; 66 | 67 | CSSSelectorSequence* seq = [[CSSSelectorSequence alloc] init]; 68 | seq.universalOrTypeSelector = [[CSSUniversalSelector alloc] init]; 69 | [seq addSelector:classSelector]; 70 | [visitor visit:seq]; 71 | 72 | NSString* xpath = [visitor xpathString]; 73 | [[xpath should] equal:@"*[contains(concat(' ', normalize-space(@class), ' '), ' red ')]"]; 74 | }); 75 | 76 | it(@"render xpath for CSSCombinator", ^{ 77 | CSSCombinator* selector = [[CSSCombinator alloc] init]; 78 | selector.type = CSSCombinatorTypeNone; 79 | [visitor visit:selector]; 80 | 81 | NSString* xpath = [visitor xpathString]; 82 | [[xpath should] equal:@"//"]; 83 | }); 84 | 85 | it(@"render xpath for CSSSelectors", ^{ 86 | CSSClassSelector* classSelector = [[CSSClassSelector alloc] init]; 87 | classSelector.name = @"red"; 88 | 89 | CSSSelectorSequence* seq = [[CSSSelectorSequence alloc] init]; 90 | seq.universalOrTypeSelector = [[CSSUniversalSelector alloc] init]; 91 | [seq addSelector:classSelector]; 92 | 93 | CSSSelectors* selectors = [[CSSSelectors alloc] init]; 94 | [selectors addSelector:seq]; 95 | [visitor visit:selectors]; 96 | 97 | NSString* xpath = [visitor xpathString]; 98 | [[xpath should] equal:@"//*[contains(concat(' ', normalize-space(@class), ' '), ' red ')]"]; 99 | }); 100 | 101 | it(@"render xpath for CSSSelectorGroup", ^{ 102 | CSSClassSelector* classSelector = [[CSSClassSelector alloc] init]; 103 | classSelector.name = @"red"; 104 | 105 | CSSSelectorSequence* seq = [[CSSSelectorSequence alloc] init]; 106 | seq.universalOrTypeSelector = [[CSSTypeSelector alloc] init]; 107 | seq.universalOrTypeSelector.name = @"table"; 108 | [seq addSelector:classSelector]; 109 | 110 | CSSSelectors* selectors = [[CSSSelectors alloc] init]; 111 | [selectors addSelector:seq]; 112 | 113 | CSSSelectorSequence* seq2 = [[CSSSelectorSequence alloc] init]; 114 | seq2.universalOrTypeSelector = [[CSSTypeSelector alloc] init]; 115 | seq2.universalOrTypeSelector.name = @"a"; 116 | CSSSelectors* selectors2 = [[CSSSelectors alloc] init]; 117 | [selectors2 addSelector:seq2]; 118 | 119 | CSSSelectorGroup* group = [[CSSSelectorGroup alloc] init]; 120 | [group addSelectors:selectors]; 121 | [group addSelectors:selectors2]; 122 | [visitor visit:group]; 123 | 124 | NSString* xpath = [visitor xpathString]; 125 | [[xpath should] equal:@"//table[contains(concat(' ', normalize-space(@class), ' '), ' red ')] | //a"]; 126 | }); 127 | 128 | context(@"render xpath for attribute", ^{ 129 | it(@"render xpath for equal attribute", ^{ 130 | CSSSelectorAttribute* attr = [[CSSSelectorAttribute alloc] init]; 131 | attr.name = @"width"; 132 | attr.value = @"30"; 133 | attr.attributeOperator = [[CSSSelectorAttributeOperator alloc] init]; 134 | attr.attributeOperator.attributeOperator = CSSSelectorAttributeOperatorTypeEqual; 135 | [visitor visit:attr]; 136 | 137 | NSString* xpath = [visitor xpathString]; 138 | [[xpath should] equal:@"@width = \"30\""]; 139 | }); 140 | 141 | it(@"render xpath for includes attribute", ^{ 142 | CSSSelectorAttribute* attr = [[CSSSelectorAttribute alloc] init]; 143 | attr.name = @"class"; 144 | attr.value = @"red"; 145 | attr.attributeOperator = [[CSSSelectorAttributeOperator alloc] init]; 146 | attr.attributeOperator.attributeOperator = CSSSelectorAttributeOperatorTypeIncludes; 147 | [visitor visit:attr]; 148 | 149 | NSString* xpath = [visitor xpathString]; 150 | [[xpath should] equal:@"contains(concat(\" \", @class, \" \"),concat(\" \", \"red\", \" \"))"]; 151 | }); 152 | 153 | it(@"render xpath for equal attribute", ^{ 154 | CSSSelectorAttribute* attr = [[CSSSelectorAttribute alloc] init]; 155 | attr.name = @"class"; 156 | attr.value = @"red"; 157 | attr.attributeOperator = [[CSSSelectorAttributeOperator alloc] init]; 158 | attr.attributeOperator.attributeOperator = CSSSelectorAttributeOperatorTypeDash; 159 | [visitor visit:attr]; 160 | 161 | NSString* xpath = [visitor xpathString]; 162 | [[xpath should] equal:@"@class = \"red\" or starts-with(@class, concat(\"red\", '-'))"]; 163 | }); 164 | }); 165 | 166 | context(@"render xpath for pseudo class", ^{ 167 | it(@"render xpath for equal attribute", ^{ 168 | CSSSelectorAttribute* attr = [[CSSSelectorAttribute alloc] init]; 169 | attr.name = @"width"; 170 | attr.value = @"30"; 171 | attr.attributeOperator = [[CSSSelectorAttributeOperator alloc] init]; 172 | attr.attributeOperator.attributeOperator = CSSSelectorAttributeOperatorTypeEqual; 173 | [visitor visit:attr]; 174 | 175 | NSString* xpath = [visitor xpathString]; 176 | [[xpath should] equal:@"@width = \"30\""]; 177 | }); 178 | }); 179 | }); 180 | 181 | SPEC_END 182 | -------------------------------------------------------------------------------- /CSSSelectorConverter/CSSSelectorXPathVisitor.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorXPathVisitor.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CSSSelectorXPathVisitor.h" 10 | 11 | #import "CSSUniversalSelector.h" 12 | #import "CSSNamedSelector.h" 13 | #import "CSSTypeSelector.h" 14 | #import "CSSIDSelector.h" 15 | #import "CSSClassSelector.h" 16 | #import "CSSSelectorSequence.h" 17 | #import "CSSSelectors.h" 18 | #import "CSSSelectorGroup.h" 19 | #import "CSSSelectorParser.h" 20 | #import "CSSSelectorAttribute.h" 21 | #import "CSSNamedSelector.h" 22 | #import "CSSCombinator.h" 23 | #import "CSSNamedSelector.h" 24 | #import "CSSPseudoClass.h" 25 | 26 | @interface CSSSelectorXPathVisitor() 27 | @property (nonatomic, strong) NSMutableString* output; 28 | @end 29 | 30 | @implementation CSSSelectorXPathVisitor 31 | 32 | -(instancetype) init { 33 | self = [super init]; 34 | self.output = [[NSMutableString alloc] init]; 35 | return self; 36 | } 37 | 38 | #pragma mark - Public 39 | 40 | -(void) visit:(CSSBaseSelector*)object { 41 | Class class = [object class]; 42 | while (class && class != [NSObject class]) 43 | { 44 | NSString *methodName = [NSString stringWithFormat:@"visit%@:", class]; 45 | SEL selector = NSSelectorFromString(methodName); 46 | if ([self respondsToSelector:selector]) 47 | { 48 | IMP imp = [self methodForSelector:selector]; 49 | void (*func)(id, SEL, id) = (void *)imp; 50 | func(self, selector, object); 51 | return; 52 | } 53 | class = [class superclass]; 54 | }; 55 | [NSException raise:NSInvalidArgumentException format:@"Not a acceptable CSSBaseSelector subclasses"]; 56 | } 57 | 58 | 59 | -(NSString*) xpathString 60 | { 61 | return [_output copy]; 62 | } 63 | 64 | -(void) appendXPath:(NSString*)string 65 | { 66 | [self.output appendString:string]; 67 | } 68 | 69 | #pragma mark - Visitors 70 | 71 | -(void) visitCSSSelectorGroup:(CSSSelectorGroup*)node 72 | { 73 | NSArray* sequence = [node.selectors copy]; 74 | [sequence enumerateObjectsUsingBlock:^(CSSBaseSelector* selector, NSUInteger idx, BOOL *stop) { 75 | [self visit:selector]; 76 | if (idx < sequence.count-1) { 77 | [self appendXPath:@" | "]; 78 | } 79 | }]; 80 | } 81 | 82 | -(void) visitCSSUniversalSelector:(CSSUniversalSelector*)node 83 | { 84 | [self appendXPath:@"*"]; 85 | } 86 | 87 | -(void) visitCSSTypeSelector:(CSSTypeSelector*)node 88 | { 89 | [self appendXPath:[NSString stringWithFormat:@"%@", node.name]]; 90 | } 91 | 92 | -(void) visitCSSIDSelector:(CSSIDSelector*)node 93 | { 94 | [self appendXPath:[NSString stringWithFormat:@"@id = '%@'", node.name]]; 95 | } 96 | 97 | -(void) visitCSSClassSelector:(CSSClassSelector*)node 98 | { 99 | [self appendXPath:[NSString stringWithFormat:@"contains(concat(' ', normalize-space(@class), ' '), ' %@ ')", node.name]]; 100 | } 101 | 102 | -(void) visitCSSSelectorSequence:(CSSSelectorSequence*)node 103 | { 104 | if (!node.universalOrTypeSelector) { 105 | node.universalOrTypeSelector = [CSSUniversalSelector selector]; 106 | } 107 | 108 | if (node.pseudoClass) { 109 | node.pseudoClass.parent = node.universalOrTypeSelector; 110 | [self visit:node.pseudoClass]; 111 | } else { 112 | [self visit:node.universalOrTypeSelector]; 113 | } 114 | 115 | if ([node.otherSelectors count] > 0) { 116 | [self appendXPath:@"["]; 117 | [node.otherSelectors enumerateObjectsUsingBlock:^(CSSBaseSelector* selector, NSUInteger idx, BOOL *stop) { 118 | [self visit:selector]; 119 | if (idx < node.otherSelectors.count - 1) { 120 | [self appendXPath:@" and "]; 121 | } 122 | }]; 123 | [self appendXPath:@"]"]; 124 | } 125 | } 126 | 127 | -(void) visitCSSCombinator:(CSSCombinator*)node 128 | { 129 | switch (node.type) { 130 | case CSSCombinatorTypeNone: 131 | { 132 | [self appendXPath:@"//"]; 133 | } 134 | break; 135 | case CSSCombinatorTypeDescendant: 136 | { 137 | [self appendXPath:@"/"]; 138 | } 139 | break; 140 | case CSSCombinatorTypeAdjacent: 141 | { 142 | [self appendXPath:@"/following-sibling::*[1]/self::"]; 143 | } 144 | break; 145 | case CSSCombinatorTypeGeneralSibling: 146 | { 147 | [self appendXPath:@"/following-sibling::"]; 148 | } 149 | break; 150 | } 151 | } 152 | 153 | -(void) visitCSSSelectors:(CSSSelectors*)node 154 | { 155 | [node.selectors enumerateObjectsUsingBlock:^(CSSBaseSelector* selector, NSUInteger idx, BOOL *stop) { 156 | // added NSStringFromClass() to work around for isKindOfClass: match error in unit test 157 | BOOL isSequence = [selector isKindOfClass:[CSSSelectorSequence class]] || [NSStringFromClass([selector class]) isEqualToString:NSStringFromClass([CSSSelectorSequence class])]; 158 | BOOL hasCombinator = idx == 0 || (![[node.selectors objectAtIndex:idx - 1] isKindOfClass:[CSSCombinator class]] && ![NSStringFromClass([[node.selectors objectAtIndex:idx - 1] class]) isEqualToString:NSStringFromClass([CSSCombinator class])]); 159 | 160 | if (isSequence && hasCombinator) { 161 | [self visit:[CSSCombinator noneCombinator]]; 162 | } 163 | [self visit:selector]; 164 | }]; 165 | } 166 | 167 | -(void) visitCSSSelectorAttribute:(CSSSelectorAttribute*)node 168 | { 169 | if (node.value) { 170 | switch (node.attributeOperator.attributeOperator) { 171 | case CSSSelectorAttributeOperatorTypeEqual: { 172 | [self appendXPath:[NSString stringWithFormat:@"@%@ = \"%@\"", node.name, node.value]]; 173 | } 174 | break; 175 | case CSSSelectorAttributeOperatorTypeIncludes: { 176 | [self appendXPath:[NSString stringWithFormat:@"contains(concat(\" \", @%@, \" \"),concat(\" \", \"%@\", \" \"))", node.name, node.value]]; 177 | } 178 | break; 179 | case CSSSelectorAttributeOperatorTypeDash: { 180 | [self appendXPath:[NSString stringWithFormat:@"@%@ = \"%@\" or starts-with(@%@, concat(\"%@\", '-'))", node.name, node.value, node.name, node.value]]; 181 | } 182 | break; 183 | case CSSSelectorAttributeOperatorTypeNone: { 184 | [self appendXPath:[NSString stringWithFormat:@"@%@", node.name]]; 185 | } 186 | break; 187 | } 188 | } else { 189 | [self appendXPath:[NSString stringWithFormat:@"@%@", node.name]]; 190 | } 191 | 192 | } 193 | 194 | -(void) visitCSSPseudoClass:(CSSPseudoClass*)node 195 | { 196 | NSString* parentName = node.parent ? node.parent.name : @"*"; 197 | NSString* mapping = [[self class] pseudoClassXPathMapping][node.name]; 198 | if (mapping) { 199 | [self appendXPath:[NSString stringWithFormat:mapping, parentName]]; 200 | } 201 | } 202 | 203 | #pragma mark - 204 | 205 | 206 | +(NSArray*) supportedPseudoClass { 207 | return [[self pseudoClassXPathMapping] allKeys]; 208 | } 209 | 210 | +(NSDictionary*) pseudoClassXPathMapping { 211 | static NSDictionary* _pseudoClassXPathMapping; 212 | static dispatch_once_t onceToken; 213 | dispatch_once(&onceToken, ^{ 214 | _pseudoClassXPathMapping = @{ 215 | @"first-child": @"*[position() = 1 and self::%@]", 216 | @"last-child": @"*[position() = last() and self::%@]", 217 | @"first-of-type": @"%@[position() = 1]", 218 | @"last-of-type":@"%@[position() = last()]", 219 | @"only-child": @"*[last() = 1 and self::%@]", 220 | @"only-of-type": @"%@[last() = 1]", 221 | @"empty": @"%@[not(node())]" 222 | }; 223 | }); 224 | return _pseudoClassXPathMapping; 225 | } 226 | 227 | @end 228 | -------------------------------------------------------------------------------- /CSSSelectorConverter/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /CSSSelectorConverterTests/CSSSelectorTokeniserSpec.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSSSelectorTokeniserSpec.m 3 | // CSSSelectorConverter 4 | // 5 | // Created by Francis Chong on 1/20/14. 6 | // Copyright 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CSSSelectorTokeniser.h" 11 | #import "NUIParse.h" 12 | 13 | SPEC_BEGIN(CSSSelectorTokeniserSpec) 14 | 15 | describe(@"CSSSelectorTokeniser", ^{ 16 | it(@"tokenize basic css", ^{ 17 | CSSSelectorTokeniser* tokeniser = [[CSSSelectorTokeniser alloc] init]; 18 | NUIPTokenStream *tokenStream = [tokeniser tokenise:@"table"]; 19 | NUIPTokenStream *expected = [NUIPTokenStream tokenStreamWithTokens:[NSArray arrayWithObjects: 20 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 21 | [NUIPEOFToken eof], 22 | nil]]; 23 | [[tokenStream should] equal:expected]; 24 | 25 | tokenStream = [tokeniser tokenise:@"table.a"]; 26 | expected = [NUIPTokenStream tokenStreamWithTokens:@[ 27 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 28 | [NUIPKeywordToken tokenWithKeyword:@"."], 29 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 30 | [NUIPEOFToken eof] 31 | ]]; 32 | [[tokenStream should] equal:expected]; 33 | }); 34 | 35 | it(@"tokenize complex selector", ^{ 36 | CSSSelectorTokeniser* tokeniser = [[CSSSelectorTokeniser alloc] init]; 37 | NUIPTokenStream *tokenStream = [tokeniser tokenise:@"table a"]; 38 | NUIPTokenStream *expected = [NUIPTokenStream tokenStreamWithTokens:@[ 39 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 40 | [NUIPWhiteSpaceToken whiteSpace:@" "], 41 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 42 | [NUIPEOFToken eof] 43 | ]]; 44 | [[tokenStream should] equal:expected]; 45 | 46 | tokenStream = [tokeniser tokenise:@"table > a"]; 47 | expected = [NUIPTokenStream tokenStreamWithTokens:@[ 48 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 49 | [NUIPKeywordToken tokenWithKeyword:@">"], 50 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 51 | [NUIPEOFToken eof] 52 | ]]; 53 | [[tokenStream should] equal:expected]; 54 | 55 | tokenStream = [tokeniser tokenise:@"table ~ a"]; 56 | expected = [NUIPTokenStream tokenStreamWithTokens:@[ 57 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 58 | [NUIPKeywordToken tokenWithKeyword:@"~"], 59 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 60 | [NUIPEOFToken eof] 61 | ]]; 62 | [[tokenStream should] equal:expected]; 63 | 64 | tokenStream = [tokeniser tokenise:@"table ~ a"]; 65 | expected = [NUIPTokenStream tokenStreamWithTokens:@[ 66 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 67 | [NUIPKeywordToken tokenWithKeyword:@"~"], 68 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 69 | [NUIPEOFToken eof] 70 | ]]; 71 | [[tokenStream should] equal:expected]; 72 | 73 | tokenStream = [tokeniser tokenise:@"table , a"]; 74 | expected = [NUIPTokenStream tokenStreamWithTokens:@[ 75 | [NUIPIdentifierToken tokenWithIdentifier:@"table"], 76 | [NUIPKeywordToken tokenWithKeyword:@","], 77 | [NUIPIdentifierToken tokenWithIdentifier:@"a"], 78 | [NUIPEOFToken eof] 79 | ]]; 80 | [[tokenStream should] equal:expected]; 81 | }); 82 | 83 | it(@"tokenize pseudo class", ^{ 84 | CSSSelectorTokeniser* tokeniser = [[CSSSelectorTokeniser alloc] init]; 85 | NUIPTokenStream *tokenStream = [tokeniser tokenise:@"div > p:first-child"]; 86 | NUIPTokenStream *expected = [NUIPTokenStream tokenStreamWithTokens:@[ 87 | [NUIPIdentifierToken tokenWithIdentifier:@"div"], 88 | [NUIPKeywordToken tokenWithKeyword:@">"], 89 | [NUIPIdentifierToken tokenWithIdentifier:@"p"], 90 | [NUIPKeywordToken tokenWithKeyword:@":"], 91 | [NUIPIdentifierToken tokenWithIdentifier:@"first-child"], 92 | [NUIPEOFToken eof]]]; 93 | [[tokenStream should] equal:expected]; 94 | }); 95 | 96 | it(@"tokenize attribute", ^{ 97 | CSSSelectorTokeniser* tokeniser = [[CSSSelectorTokeniser alloc] init]; 98 | NUIPTokenStream *tokenStream = [tokeniser tokenise:@"div[class~=\"100\"]"]; 99 | NUIPTokenStream *expected = [NUIPTokenStream tokenStreamWithTokens:[NSArray arrayWithObjects: 100 | [NUIPIdentifierToken tokenWithIdentifier:@"div"], 101 | [NUIPKeywordToken tokenWithKeyword:@"["], 102 | [NUIPIdentifierToken tokenWithIdentifier:@"class"], 103 | [NUIPKeywordToken tokenWithKeyword:@"~="], 104 | [NUIPQuotedToken content:@"100" quotedWith:@"\"" name:@"String"], 105 | [NUIPKeywordToken tokenWithKeyword:@"]"], 106 | [NUIPEOFToken eof], 107 | nil]]; 108 | [[tokenStream should] equal:expected]; 109 | 110 | tokenStream = [tokeniser tokenise:@"div[class |= \"100\"]"]; 111 | expected = [NUIPTokenStream tokenStreamWithTokens:[NSArray arrayWithObjects: 112 | [NUIPIdentifierToken tokenWithIdentifier:@"div"], 113 | [NUIPKeywordToken tokenWithKeyword:@"["], 114 | [NUIPIdentifierToken tokenWithIdentifier:@"class"], 115 | [NUIPKeywordToken tokenWithKeyword:@"|="], 116 | [NUIPQuotedToken content:@"100" quotedWith:@"\"" name:@"String"], 117 | [NUIPKeywordToken tokenWithKeyword:@"]"], 118 | [NUIPEOFToken eof], 119 | nil]]; 120 | [[tokenStream should] equal:expected]; 121 | 122 | tokenStream = [tokeniser tokenise:@"div[class = '100']"]; 123 | expected = [NUIPTokenStream tokenStreamWithTokens:[NSArray arrayWithObjects: 124 | [NUIPIdentifierToken tokenWithIdentifier:@"div"], 125 | [NUIPKeywordToken tokenWithKeyword:@"["], 126 | [NUIPIdentifierToken tokenWithIdentifier:@"class"], 127 | [NUIPKeywordToken tokenWithKeyword:@"="], 128 | [NUIPQuotedToken content:@"100" quotedWith:@"'" name:@"String"], 129 | [NUIPKeywordToken tokenWithKeyword:@"]"], 130 | [NUIPEOFToken eof], 131 | nil]]; 132 | [[tokenStream should] equal:expected]; 133 | }); 134 | 135 | }); 136 | 137 | SPEC_END 138 | -------------------------------------------------------------------------------- /CSSSelectorConverter.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 314EB2B033004B6F82F43722 /* libPods-CSSSelectorConverterTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C89C0A8F74244B1F8AECA338 /* libPods-CSSSelectorConverterTests.a */; }; 11 | 4E9F91BE36C84A6FA954D8C1 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 645CC76B14924389A7C750E3 /* libPods.a */; }; 12 | 540AA34C187BC5F60012AA44 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA34B187BC5F60012AA44 /* Foundation.framework */; }; 13 | 540AA34E187BC5F60012AA44 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA34D187BC5F60012AA44 /* CoreGraphics.framework */; }; 14 | 540AA350187BC5F60012AA44 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA34F187BC5F60012AA44 /* UIKit.framework */; }; 15 | 540AA356187BC5F60012AA44 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 540AA354187BC5F60012AA44 /* InfoPlist.strings */; }; 16 | 540AA358187BC5F60012AA44 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA357187BC5F60012AA44 /* main.m */; }; 17 | 540AA35C187BC5F60012AA44 /* IGAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA35B187BC5F60012AA44 /* IGAppDelegate.m */; }; 18 | 540AA35F187BC5F60012AA44 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 540AA35D187BC5F60012AA44 /* Main.storyboard */; }; 19 | 540AA362187BC5F60012AA44 /* IGMasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA361187BC5F60012AA44 /* IGMasterViewController.m */; }; 20 | 540AA365187BC5F60012AA44 /* IGDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA364187BC5F60012AA44 /* IGDetailViewController.m */; }; 21 | 540AA367187BC5F70012AA44 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 540AA366187BC5F70012AA44 /* Images.xcassets */; }; 22 | 540AA36E187BC5F70012AA44 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA36D187BC5F70012AA44 /* XCTest.framework */; }; 23 | 540AA36F187BC5F70012AA44 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA34B187BC5F60012AA44 /* Foundation.framework */; }; 24 | 540AA370187BC5F70012AA44 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540AA34F187BC5F60012AA44 /* UIKit.framework */; }; 25 | 540AA378187BC5F70012AA44 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 540AA376187BC5F70012AA44 /* InfoPlist.strings */; }; 26 | 5419722F188FB97E004240B4 /* CSSSelectorXPathVisitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5419722E188FB97E004240B4 /* CSSSelectorXPathVisitor.m */; }; 27 | 54197231188FBAF0004240B4 /* CSSSelectorXPathVisitorSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 54197230188FBAF0004240B4 /* CSSSelectorXPathVisitorSpec.m */; }; 28 | 5433BA57188D0C5B006C5F59 /* CSSSelectorTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = 5433BA56188D0C5B006C5F59 /* CSSSelectorTokeniser.m */; }; 29 | 5433BA5B188D0D71006C5F59 /* CSSSelectorTokeniserSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5433BA59188D0D71006C5F59 /* CSSSelectorTokeniserSpec.m */; }; 30 | 5433BA5E188D136A006C5F59 /* CSSSelectorGrammar.m in Sources */ = {isa = PBXBuildFile; fileRef = 5433BA5D188D136A006C5F59 /* CSSSelectorGrammar.m */; }; 31 | 5433BA61188D1450006C5F59 /* CSSSelectorGrammar.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5433BA60188D1450006C5F59 /* CSSSelectorGrammar.txt */; }; 32 | 5433BA63188D1629006C5F59 /* CSSSelectorParserSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5433BA62188D1629006C5F59 /* CSSSelectorParserSpec.m */; }; 33 | 5433BA64188D17CE006C5F59 /* CSSSelectorGrammar.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5433BA60188D1450006C5F59 /* CSSSelectorGrammar.txt */; }; 34 | 5433BA66188D1808006C5F59 /* CSSUniversalSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3A1187BEF380012AA44 /* CSSUniversalSelector.m */; }; 35 | 5433BA6F188D1940006C5F59 /* CSSNamedSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3B1187BF1660012AA44 /* CSSNamedSelector.m */; }; 36 | 5433BA70188D1949006C5F59 /* CSSBaseSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3B5187BF2D60012AA44 /* CSSBaseSelector.m */; }; 37 | 5433BA72188D1D9E006C5F59 /* CSSTypeSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3A5187BEF8B0012AA44 /* CSSTypeSelector.m */; }; 38 | 54BC925B188E736000443230 /* CSSSelectors.m in Sources */ = {isa = PBXBuildFile; fileRef = 543F5AA6187C0A1D00F3CC22 /* CSSSelectors.m */; }; 39 | 54BC925D188E770A00443230 /* CSSSelectorGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 54D62F26187D06150075A755 /* CSSSelectorGroup.m */; }; 40 | 54D41BAA188E7A9D00D8521A /* CSSPseudoClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 541EC707187D589000F08D19 /* CSSPseudoClass.m */; }; 41 | 54ECE0CF1890F23500C2A4ED /* CSSSelectorParser.plist in Resources */ = {isa = PBXBuildFile; fileRef = 54ECE0CE1890F23500C2A4ED /* CSSSelectorParser.plist */; }; 42 | 54ECE0D01890F23500C2A4ED /* CSSSelectorParser.plist in Resources */ = {isa = PBXBuildFile; fileRef = 54ECE0CE1890F23500C2A4ED /* CSSSelectorParser.plist */; }; 43 | 54FA2F71188D76AA0065B628 /* CSSClassSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3AD187BF1510012AA44 /* CSSClassSelector.m */; }; 44 | 54FA2F72188D7AEB0065B628 /* CSSSelectorParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA39C187BEE660012AA44 /* CSSSelectorParser.m */; }; 45 | 54FA2F74188D7C650065B628 /* CSSSelectorToXPathConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA397187BE4900012AA44 /* CSSSelectorToXPathConverter.m */; }; 46 | 54FA2F76188D7CDD0065B628 /* CSSToXPathConverterSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA388187BDD5B0012AA44 /* CSSToXPathConverterSpec.m */; }; 47 | 54FA2F79188D826F0065B628 /* CSSIDSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3A9187BF1460012AA44 /* CSSIDSelector.m */; }; 48 | 54FA2F7D188D867F0065B628 /* CSSSelectorAttribute.m in Sources */ = {isa = PBXBuildFile; fileRef = 548A92A0187D1CF70045D4CA /* CSSSelectorAttribute.m */; }; 49 | 54FA2F80188D88BA0065B628 /* CSSSelectorAttributeOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 541EC6FF187D34AB00F08D19 /* CSSSelectorAttributeOperator.m */; }; 50 | 54FA2F82188D8E6C0065B628 /* CSSCombinator.m in Sources */ = {isa = PBXBuildFile; fileRef = 541EC703187D43A300F08D19 /* CSSCombinator.m */; }; 51 | 54FA2F84188D8F610065B628 /* CSSSelectorSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = 540AA3B9187BF3630012AA44 /* CSSSelectorSequence.m */; }; 52 | /* End PBXBuildFile section */ 53 | 54 | /* Begin PBXContainerItemProxy section */ 55 | 540AA371187BC5F70012AA44 /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = 540AA340187BC5F60012AA44 /* Project object */; 58 | proxyType = 1; 59 | remoteGlobalIDString = 540AA347187BC5F60012AA44; 60 | remoteInfo = CSSSelectorConverter; 61 | }; 62 | /* End PBXContainerItemProxy section */ 63 | 64 | /* Begin PBXFileReference section */ 65 | 2FA369A0A3C034B1BA4E570B /* Pods-CSSSelectorConverterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CSSSelectorConverterTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CSSSelectorConverterTests/Pods-CSSSelectorConverterTests.release.xcconfig"; sourceTree = ""; }; 66 | 31A43E848921BC4A334A76A7 /* Pods-CSSSelectorConverterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CSSSelectorConverterTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CSSSelectorConverterTests/Pods-CSSSelectorConverterTests.debug.xcconfig"; sourceTree = ""; }; 67 | 4654C27EDB914CB3303D3F76 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 68 | 48679CA62B498976F68DA0ED /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 69 | 540AA348187BC5F60012AA44 /* CSSSelectorConverter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CSSSelectorConverter.app; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 540AA34B187BC5F60012AA44 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 71 | 540AA34D187BC5F60012AA44 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 72 | 540AA34F187BC5F60012AA44 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 73 | 540AA353187BC5F60012AA44 /* CSSSelectorConverter-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CSSSelectorConverter-Info.plist"; sourceTree = ""; }; 74 | 540AA355187BC5F60012AA44 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 75 | 540AA357187BC5F60012AA44 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 76 | 540AA359187BC5F60012AA44 /* CSSSelectorConverter-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CSSSelectorConverter-Prefix.pch"; sourceTree = ""; }; 77 | 540AA35A187BC5F60012AA44 /* IGAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IGAppDelegate.h; sourceTree = ""; }; 78 | 540AA35B187BC5F60012AA44 /* IGAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IGAppDelegate.m; sourceTree = ""; }; 79 | 540AA35E187BC5F60012AA44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 80 | 540AA360187BC5F60012AA44 /* IGMasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IGMasterViewController.h; sourceTree = ""; }; 81 | 540AA361187BC5F60012AA44 /* IGMasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IGMasterViewController.m; sourceTree = ""; }; 82 | 540AA363187BC5F60012AA44 /* IGDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IGDetailViewController.h; sourceTree = ""; }; 83 | 540AA364187BC5F60012AA44 /* IGDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IGDetailViewController.m; sourceTree = ""; }; 84 | 540AA366187BC5F70012AA44 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 85 | 540AA36C187BC5F70012AA44 /* CSSSelectorConverterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CSSSelectorConverterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | 540AA36D187BC5F70012AA44 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 87 | 540AA375187BC5F70012AA44 /* CSSSelectorConverterTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CSSSelectorConverterTests-Info.plist"; sourceTree = ""; }; 88 | 540AA377187BC5F70012AA44 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 89 | 540AA388187BDD5B0012AA44 /* CSSToXPathConverterSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSToXPathConverterSpec.m; sourceTree = ""; }; 90 | 540AA396187BE4900012AA44 /* CSSSelectorToXPathConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorToXPathConverter.h; sourceTree = ""; }; 91 | 540AA397187BE4900012AA44 /* CSSSelectorToXPathConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorToXPathConverter.m; sourceTree = ""; }; 92 | 540AA39B187BEE660012AA44 /* CSSSelectorParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorParser.h; sourceTree = ""; }; 93 | 540AA39C187BEE660012AA44 /* CSSSelectorParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorParser.m; sourceTree = ""; }; 94 | 540AA3A0187BEF380012AA44 /* CSSUniversalSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSUniversalSelector.h; sourceTree = ""; }; 95 | 540AA3A1187BEF380012AA44 /* CSSUniversalSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSUniversalSelector.m; sourceTree = ""; }; 96 | 540AA3A4187BEF8B0012AA44 /* CSSTypeSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSTypeSelector.h; sourceTree = ""; }; 97 | 540AA3A5187BEF8B0012AA44 /* CSSTypeSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSTypeSelector.m; sourceTree = ""; }; 98 | 540AA3A8187BF1460012AA44 /* CSSIDSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSIDSelector.h; sourceTree = ""; }; 99 | 540AA3A9187BF1460012AA44 /* CSSIDSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSIDSelector.m; sourceTree = ""; }; 100 | 540AA3AC187BF1510012AA44 /* CSSClassSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSClassSelector.h; sourceTree = ""; }; 101 | 540AA3AD187BF1510012AA44 /* CSSClassSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSClassSelector.m; sourceTree = ""; }; 102 | 540AA3B0187BF1660012AA44 /* CSSNamedSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSNamedSelector.h; sourceTree = ""; }; 103 | 540AA3B1187BF1660012AA44 /* CSSNamedSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSNamedSelector.m; sourceTree = ""; }; 104 | 540AA3B4187BF2D60012AA44 /* CSSBaseSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSBaseSelector.h; sourceTree = ""; }; 105 | 540AA3B5187BF2D60012AA44 /* CSSBaseSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSBaseSelector.m; sourceTree = ""; }; 106 | 540AA3B8187BF3630012AA44 /* CSSSelectorSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorSequence.h; sourceTree = ""; }; 107 | 540AA3B9187BF3630012AA44 /* CSSSelectorSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorSequence.m; sourceTree = ""; }; 108 | 5419722D188FB97E004240B4 /* CSSSelectorXPathVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorXPathVisitor.h; sourceTree = ""; }; 109 | 5419722E188FB97E004240B4 /* CSSSelectorXPathVisitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorXPathVisitor.m; sourceTree = ""; }; 110 | 54197230188FBAF0004240B4 /* CSSSelectorXPathVisitorSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorXPathVisitorSpec.m; sourceTree = ""; }; 111 | 541EC6FE187D34AB00F08D19 /* CSSSelectorAttributeOperator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorAttributeOperator.h; sourceTree = ""; }; 112 | 541EC6FF187D34AB00F08D19 /* CSSSelectorAttributeOperator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorAttributeOperator.m; sourceTree = ""; }; 113 | 541EC702187D43A300F08D19 /* CSSCombinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSCombinator.h; sourceTree = ""; }; 114 | 541EC703187D43A300F08D19 /* CSSCombinator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSCombinator.m; sourceTree = ""; }; 115 | 541EC706187D589000F08D19 /* CSSPseudoClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSPseudoClass.h; sourceTree = ""; }; 116 | 541EC707187D589000F08D19 /* CSSPseudoClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSPseudoClass.m; sourceTree = ""; }; 117 | 5433BA55188D0C5B006C5F59 /* CSSSelectorTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorTokeniser.h; sourceTree = ""; }; 118 | 5433BA56188D0C5B006C5F59 /* CSSSelectorTokeniser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorTokeniser.m; sourceTree = ""; }; 119 | 5433BA59188D0D71006C5F59 /* CSSSelectorTokeniserSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorTokeniserSpec.m; sourceTree = ""; }; 120 | 5433BA5C188D136A006C5F59 /* CSSSelectorGrammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorGrammar.h; sourceTree = ""; }; 121 | 5433BA5D188D136A006C5F59 /* CSSSelectorGrammar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorGrammar.m; sourceTree = ""; }; 122 | 5433BA60188D1450006C5F59 /* CSSSelectorGrammar.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CSSSelectorGrammar.txt; sourceTree = ""; }; 123 | 5433BA62188D1629006C5F59 /* CSSSelectorParserSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorParserSpec.m; sourceTree = ""; }; 124 | 543F5AA5187C0A1D00F3CC22 /* CSSSelectors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectors.h; sourceTree = ""; }; 125 | 543F5AA6187C0A1D00F3CC22 /* CSSSelectors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectors.m; sourceTree = ""; }; 126 | 548A929F187D1CF70045D4CA /* CSSSelectorAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorAttribute.h; sourceTree = ""; }; 127 | 548A92A0187D1CF70045D4CA /* CSSSelectorAttribute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorAttribute.m; sourceTree = ""; }; 128 | 54D62F25187D06150075A755 /* CSSSelectorGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorGroup.h; sourceTree = ""; }; 129 | 54D62F26187D06150075A755 /* CSSSelectorGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorGroup.m; sourceTree = ""; }; 130 | 54D62F29187D0B0E0075A755 /* CSSSelectorConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSSSelectorConverter.h; sourceTree = ""; }; 131 | 54ECE09A1890D30000C2A4ED /* libPods.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libPods.a; path = "Pods/build/Debug-iphoneos/libPods.a"; sourceTree = ""; }; 132 | 54ECE0B81890D5C700C2A4ED /* CSSSelectorParserGenerator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorParserGenerator.m; sourceTree = ""; }; 133 | 54ECE0CE1890F23500C2A4ED /* CSSSelectorParser.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = CSSSelectorParser.plist; sourceTree = ""; }; 134 | 645CC76B14924389A7C750E3 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 135 | C89C0A8F74244B1F8AECA338 /* libPods-CSSSelectorConverterTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CSSSelectorConverterTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 136 | /* End PBXFileReference section */ 137 | 138 | /* Begin PBXFrameworksBuildPhase section */ 139 | 540AA345187BC5F60012AA44 /* Frameworks */ = { 140 | isa = PBXFrameworksBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 540AA34E187BC5F60012AA44 /* CoreGraphics.framework in Frameworks */, 144 | 540AA350187BC5F60012AA44 /* UIKit.framework in Frameworks */, 145 | 540AA34C187BC5F60012AA44 /* Foundation.framework in Frameworks */, 146 | 4E9F91BE36C84A6FA954D8C1 /* libPods.a in Frameworks */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | 540AA369187BC5F70012AA44 /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | 540AA36E187BC5F70012AA44 /* XCTest.framework in Frameworks */, 155 | 540AA370187BC5F70012AA44 /* UIKit.framework in Frameworks */, 156 | 540AA36F187BC5F70012AA44 /* Foundation.framework in Frameworks */, 157 | 314EB2B033004B6F82F43722 /* libPods-CSSSelectorConverterTests.a in Frameworks */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXFrameworksBuildPhase section */ 162 | 163 | /* Begin PBXGroup section */ 164 | 4E499CA610DCD32F6D114FC8 /* Pods */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 48679CA62B498976F68DA0ED /* Pods.debug.xcconfig */, 168 | 4654C27EDB914CB3303D3F76 /* Pods.release.xcconfig */, 169 | 31A43E848921BC4A334A76A7 /* Pods-CSSSelectorConverterTests.debug.xcconfig */, 170 | 2FA369A0A3C034B1BA4E570B /* Pods-CSSSelectorConverterTests.release.xcconfig */, 171 | ); 172 | name = Pods; 173 | sourceTree = ""; 174 | }; 175 | 540AA33F187BC5F60012AA44 = { 176 | isa = PBXGroup; 177 | children = ( 178 | 54ECE0B71890D5C700C2A4ED /* bin */, 179 | 540AA351187BC5F60012AA44 /* CSSSelectorConverter */, 180 | 540AA373187BC5F70012AA44 /* CSSSelectorConverterTests */, 181 | 540AA34A187BC5F60012AA44 /* Frameworks */, 182 | 540AA349187BC5F60012AA44 /* Products */, 183 | 4E499CA610DCD32F6D114FC8 /* Pods */, 184 | ); 185 | sourceTree = ""; 186 | }; 187 | 540AA349187BC5F60012AA44 /* Products */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 540AA348187BC5F60012AA44 /* CSSSelectorConverter.app */, 191 | 540AA36C187BC5F70012AA44 /* CSSSelectorConverterTests.xctest */, 192 | ); 193 | name = Products; 194 | sourceTree = ""; 195 | }; 196 | 540AA34A187BC5F60012AA44 /* Frameworks */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | 54ECE09A1890D30000C2A4ED /* libPods.a */, 200 | 540AA34B187BC5F60012AA44 /* Foundation.framework */, 201 | 540AA34D187BC5F60012AA44 /* CoreGraphics.framework */, 202 | 540AA34F187BC5F60012AA44 /* UIKit.framework */, 203 | 540AA36D187BC5F70012AA44 /* XCTest.framework */, 204 | 645CC76B14924389A7C750E3 /* libPods.a */, 205 | C89C0A8F74244B1F8AECA338 /* libPods-CSSSelectorConverterTests.a */, 206 | ); 207 | name = Frameworks; 208 | sourceTree = ""; 209 | }; 210 | 540AA351187BC5F60012AA44 /* CSSSelectorConverter */ = { 211 | isa = PBXGroup; 212 | children = ( 213 | 540AA39F187BEEED0012AA44 /* Selector */, 214 | 54D62F29187D0B0E0075A755 /* CSSSelectorConverter.h */, 215 | 540AA39B187BEE660012AA44 /* CSSSelectorParser.h */, 216 | 540AA39C187BEE660012AA44 /* CSSSelectorParser.m */, 217 | 5433BA55188D0C5B006C5F59 /* CSSSelectorTokeniser.h */, 218 | 5433BA56188D0C5B006C5F59 /* CSSSelectorTokeniser.m */, 219 | 5433BA5C188D136A006C5F59 /* CSSSelectorGrammar.h */, 220 | 5433BA5D188D136A006C5F59 /* CSSSelectorGrammar.m */, 221 | 5433BA60188D1450006C5F59 /* CSSSelectorGrammar.txt */, 222 | 5419722D188FB97E004240B4 /* CSSSelectorXPathVisitor.h */, 223 | 5419722E188FB97E004240B4 /* CSSSelectorXPathVisitor.m */, 224 | 540AA396187BE4900012AA44 /* CSSSelectorToXPathConverter.h */, 225 | 540AA397187BE4900012AA44 /* CSSSelectorToXPathConverter.m */, 226 | 540AA35A187BC5F60012AA44 /* IGAppDelegate.h */, 227 | 540AA35B187BC5F60012AA44 /* IGAppDelegate.m */, 228 | 540AA35D187BC5F60012AA44 /* Main.storyboard */, 229 | 540AA360187BC5F60012AA44 /* IGMasterViewController.h */, 230 | 540AA361187BC5F60012AA44 /* IGMasterViewController.m */, 231 | 540AA363187BC5F60012AA44 /* IGDetailViewController.h */, 232 | 540AA364187BC5F60012AA44 /* IGDetailViewController.m */, 233 | 540AA366187BC5F70012AA44 /* Images.xcassets */, 234 | 540AA352187BC5F60012AA44 /* Supporting Files */, 235 | ); 236 | path = CSSSelectorConverter; 237 | sourceTree = ""; 238 | }; 239 | 540AA352187BC5F60012AA44 /* Supporting Files */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | 54ECE0CE1890F23500C2A4ED /* CSSSelectorParser.plist */, 243 | 540AA353187BC5F60012AA44 /* CSSSelectorConverter-Info.plist */, 244 | 540AA354187BC5F60012AA44 /* InfoPlist.strings */, 245 | 540AA357187BC5F60012AA44 /* main.m */, 246 | 540AA359187BC5F60012AA44 /* CSSSelectorConverter-Prefix.pch */, 247 | ); 248 | name = "Supporting Files"; 249 | sourceTree = ""; 250 | }; 251 | 540AA373187BC5F70012AA44 /* CSSSelectorConverterTests */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 540AA374187BC5F70012AA44 /* Supporting Files */, 255 | 540AA388187BDD5B0012AA44 /* CSSToXPathConverterSpec.m */, 256 | 5433BA59188D0D71006C5F59 /* CSSSelectorTokeniserSpec.m */, 257 | 5433BA62188D1629006C5F59 /* CSSSelectorParserSpec.m */, 258 | 54197230188FBAF0004240B4 /* CSSSelectorXPathVisitorSpec.m */, 259 | ); 260 | path = CSSSelectorConverterTests; 261 | sourceTree = ""; 262 | }; 263 | 540AA374187BC5F70012AA44 /* Supporting Files */ = { 264 | isa = PBXGroup; 265 | children = ( 266 | 540AA375187BC5F70012AA44 /* CSSSelectorConverterTests-Info.plist */, 267 | 540AA376187BC5F70012AA44 /* InfoPlist.strings */, 268 | ); 269 | name = "Supporting Files"; 270 | sourceTree = ""; 271 | }; 272 | 540AA39F187BEEED0012AA44 /* Selector */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 540AA3B4187BF2D60012AA44 /* CSSBaseSelector.h */, 276 | 540AA3B5187BF2D60012AA44 /* CSSBaseSelector.m */, 277 | 540AA3B0187BF1660012AA44 /* CSSNamedSelector.h */, 278 | 540AA3B1187BF1660012AA44 /* CSSNamedSelector.m */, 279 | 540AA3A4187BEF8B0012AA44 /* CSSTypeSelector.h */, 280 | 540AA3A5187BEF8B0012AA44 /* CSSTypeSelector.m */, 281 | 540AA3A0187BEF380012AA44 /* CSSUniversalSelector.h */, 282 | 540AA3A1187BEF380012AA44 /* CSSUniversalSelector.m */, 283 | 540AA3A8187BF1460012AA44 /* CSSIDSelector.h */, 284 | 540AA3A9187BF1460012AA44 /* CSSIDSelector.m */, 285 | 540AA3AC187BF1510012AA44 /* CSSClassSelector.h */, 286 | 540AA3AD187BF1510012AA44 /* CSSClassSelector.m */, 287 | 540AA3B8187BF3630012AA44 /* CSSSelectorSequence.h */, 288 | 540AA3B9187BF3630012AA44 /* CSSSelectorSequence.m */, 289 | 543F5AA5187C0A1D00F3CC22 /* CSSSelectors.h */, 290 | 543F5AA6187C0A1D00F3CC22 /* CSSSelectors.m */, 291 | 54D62F25187D06150075A755 /* CSSSelectorGroup.h */, 292 | 54D62F26187D06150075A755 /* CSSSelectorGroup.m */, 293 | 548A929F187D1CF70045D4CA /* CSSSelectorAttribute.h */, 294 | 548A92A0187D1CF70045D4CA /* CSSSelectorAttribute.m */, 295 | 541EC6FE187D34AB00F08D19 /* CSSSelectorAttributeOperator.h */, 296 | 541EC6FF187D34AB00F08D19 /* CSSSelectorAttributeOperator.m */, 297 | 541EC702187D43A300F08D19 /* CSSCombinator.h */, 298 | 541EC703187D43A300F08D19 /* CSSCombinator.m */, 299 | 541EC706187D589000F08D19 /* CSSPseudoClass.h */, 300 | 541EC707187D589000F08D19 /* CSSPseudoClass.m */, 301 | ); 302 | name = Selector; 303 | sourceTree = ""; 304 | }; 305 | 54ECE0B71890D5C700C2A4ED /* bin */ = { 306 | isa = PBXGroup; 307 | children = ( 308 | 54ECE0B81890D5C700C2A4ED /* CSSSelectorParserGenerator.m */, 309 | ); 310 | path = bin; 311 | sourceTree = ""; 312 | }; 313 | /* End PBXGroup section */ 314 | 315 | /* Begin PBXNativeTarget section */ 316 | 540AA347187BC5F60012AA44 /* CSSSelectorConverter */ = { 317 | isa = PBXNativeTarget; 318 | buildConfigurationList = 540AA37D187BC5F70012AA44 /* Build configuration list for PBXNativeTarget "CSSSelectorConverter" */; 319 | buildPhases = ( 320 | E9DFBE05A0034D26B921C88E /* Check Pods Manifest.lock */, 321 | 540AA344187BC5F60012AA44 /* Sources */, 322 | 540AA345187BC5F60012AA44 /* Frameworks */, 323 | 540AA346187BC5F60012AA44 /* Resources */, 324 | D4177FD04A764743819E8D91 /* Copy Pods Resources */, 325 | CCBB5AE69B0EE716A45BE69F /* Embed Pods Frameworks */, 326 | ); 327 | buildRules = ( 328 | ); 329 | dependencies = ( 330 | ); 331 | name = CSSSelectorConverter; 332 | productName = CSSSelectorConverter; 333 | productReference = 540AA348187BC5F60012AA44 /* CSSSelectorConverter.app */; 334 | productType = "com.apple.product-type.application"; 335 | }; 336 | 540AA36B187BC5F70012AA44 /* CSSSelectorConverterTests */ = { 337 | isa = PBXNativeTarget; 338 | buildConfigurationList = 540AA380187BC5F70012AA44 /* Build configuration list for PBXNativeTarget "CSSSelectorConverterTests" */; 339 | buildPhases = ( 340 | 24221490C75A4512A9EDB908 /* Check Pods Manifest.lock */, 341 | 540AA368187BC5F70012AA44 /* Sources */, 342 | 540AA369187BC5F70012AA44 /* Frameworks */, 343 | 540AA36A187BC5F70012AA44 /* Resources */, 344 | B54882A65CA547AA967484DE /* Copy Pods Resources */, 345 | 36C248A9A97CC7EC8A6F38F8 /* Embed Pods Frameworks */, 346 | ); 347 | buildRules = ( 348 | ); 349 | dependencies = ( 350 | 540AA372187BC5F70012AA44 /* PBXTargetDependency */, 351 | ); 352 | name = CSSSelectorConverterTests; 353 | productName = CSSSelectorConverterTests; 354 | productReference = 540AA36C187BC5F70012AA44 /* CSSSelectorConverterTests.xctest */; 355 | productType = "com.apple.product-type.bundle.unit-test"; 356 | }; 357 | /* End PBXNativeTarget section */ 358 | 359 | /* Begin PBXProject section */ 360 | 540AA340187BC5F60012AA44 /* Project object */ = { 361 | isa = PBXProject; 362 | attributes = { 363 | CLASSPREFIX = IG; 364 | LastUpgradeCheck = 0500; 365 | ORGANIZATIONNAME = "Ignition Soft"; 366 | TargetAttributes = { 367 | 540AA36B187BC5F70012AA44 = { 368 | TestTargetID = 540AA347187BC5F60012AA44; 369 | }; 370 | }; 371 | }; 372 | buildConfigurationList = 540AA343187BC5F60012AA44 /* Build configuration list for PBXProject "CSSSelectorConverter" */; 373 | compatibilityVersion = "Xcode 3.2"; 374 | developmentRegion = English; 375 | hasScannedForEncodings = 0; 376 | knownRegions = ( 377 | en, 378 | Base, 379 | ); 380 | mainGroup = 540AA33F187BC5F60012AA44; 381 | productRefGroup = 540AA349187BC5F60012AA44 /* Products */; 382 | projectDirPath = ""; 383 | projectRoot = ""; 384 | targets = ( 385 | 540AA347187BC5F60012AA44 /* CSSSelectorConverter */, 386 | 540AA36B187BC5F70012AA44 /* CSSSelectorConverterTests */, 387 | ); 388 | }; 389 | /* End PBXProject section */ 390 | 391 | /* Begin PBXResourcesBuildPhase section */ 392 | 540AA346187BC5F60012AA44 /* Resources */ = { 393 | isa = PBXResourcesBuildPhase; 394 | buildActionMask = 2147483647; 395 | files = ( 396 | 54ECE0CF1890F23500C2A4ED /* CSSSelectorParser.plist in Resources */, 397 | 540AA367187BC5F70012AA44 /* Images.xcassets in Resources */, 398 | 5433BA61188D1450006C5F59 /* CSSSelectorGrammar.txt in Resources */, 399 | 540AA356187BC5F60012AA44 /* InfoPlist.strings in Resources */, 400 | 540AA35F187BC5F60012AA44 /* Main.storyboard in Resources */, 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | 540AA36A187BC5F70012AA44 /* Resources */ = { 405 | isa = PBXResourcesBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | 54ECE0D01890F23500C2A4ED /* CSSSelectorParser.plist in Resources */, 409 | 540AA378187BC5F70012AA44 /* InfoPlist.strings in Resources */, 410 | 5433BA64188D17CE006C5F59 /* CSSSelectorGrammar.txt in Resources */, 411 | ); 412 | runOnlyForDeploymentPostprocessing = 0; 413 | }; 414 | /* End PBXResourcesBuildPhase section */ 415 | 416 | /* Begin PBXShellScriptBuildPhase section */ 417 | 24221490C75A4512A9EDB908 /* Check Pods Manifest.lock */ = { 418 | isa = PBXShellScriptBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | ); 422 | inputPaths = ( 423 | ); 424 | name = "Check Pods Manifest.lock"; 425 | outputPaths = ( 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | shellPath = /bin/sh; 429 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 430 | showEnvVarsInLog = 0; 431 | }; 432 | 36C248A9A97CC7EC8A6F38F8 /* Embed Pods Frameworks */ = { 433 | isa = PBXShellScriptBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | ); 437 | inputPaths = ( 438 | ); 439 | name = "Embed Pods Frameworks"; 440 | outputPaths = ( 441 | ); 442 | runOnlyForDeploymentPostprocessing = 0; 443 | shellPath = /bin/sh; 444 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CSSSelectorConverterTests/Pods-CSSSelectorConverterTests-frameworks.sh\"\n"; 445 | showEnvVarsInLog = 0; 446 | }; 447 | B54882A65CA547AA967484DE /* Copy Pods Resources */ = { 448 | isa = PBXShellScriptBuildPhase; 449 | buildActionMask = 2147483647; 450 | files = ( 451 | ); 452 | inputPaths = ( 453 | ); 454 | name = "Copy Pods Resources"; 455 | outputPaths = ( 456 | ); 457 | runOnlyForDeploymentPostprocessing = 0; 458 | shellPath = /bin/sh; 459 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CSSSelectorConverterTests/Pods-CSSSelectorConverterTests-resources.sh\"\n"; 460 | showEnvVarsInLog = 0; 461 | }; 462 | CCBB5AE69B0EE716A45BE69F /* Embed Pods Frameworks */ = { 463 | isa = PBXShellScriptBuildPhase; 464 | buildActionMask = 2147483647; 465 | files = ( 466 | ); 467 | inputPaths = ( 468 | ); 469 | name = "Embed Pods Frameworks"; 470 | outputPaths = ( 471 | ); 472 | runOnlyForDeploymentPostprocessing = 0; 473 | shellPath = /bin/sh; 474 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; 475 | showEnvVarsInLog = 0; 476 | }; 477 | D4177FD04A764743819E8D91 /* Copy Pods Resources */ = { 478 | isa = PBXShellScriptBuildPhase; 479 | buildActionMask = 2147483647; 480 | files = ( 481 | ); 482 | inputPaths = ( 483 | ); 484 | name = "Copy Pods Resources"; 485 | outputPaths = ( 486 | ); 487 | runOnlyForDeploymentPostprocessing = 0; 488 | shellPath = /bin/sh; 489 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 490 | showEnvVarsInLog = 0; 491 | }; 492 | E9DFBE05A0034D26B921C88E /* Check Pods Manifest.lock */ = { 493 | isa = PBXShellScriptBuildPhase; 494 | buildActionMask = 2147483647; 495 | files = ( 496 | ); 497 | inputPaths = ( 498 | ); 499 | name = "Check Pods Manifest.lock"; 500 | outputPaths = ( 501 | ); 502 | runOnlyForDeploymentPostprocessing = 0; 503 | shellPath = /bin/sh; 504 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 505 | showEnvVarsInLog = 0; 506 | }; 507 | /* End PBXShellScriptBuildPhase section */ 508 | 509 | /* Begin PBXSourcesBuildPhase section */ 510 | 540AA344187BC5F60012AA44 /* Sources */ = { 511 | isa = PBXSourcesBuildPhase; 512 | buildActionMask = 2147483647; 513 | files = ( 514 | 54FA2F82188D8E6C0065B628 /* CSSCombinator.m in Sources */, 515 | 54FA2F72188D7AEB0065B628 /* CSSSelectorParser.m in Sources */, 516 | 54BC925D188E770A00443230 /* CSSSelectorGroup.m in Sources */, 517 | 5433BA57188D0C5B006C5F59 /* CSSSelectorTokeniser.m in Sources */, 518 | 540AA362187BC5F60012AA44 /* IGMasterViewController.m in Sources */, 519 | 540AA365187BC5F60012AA44 /* IGDetailViewController.m in Sources */, 520 | 5433BA5E188D136A006C5F59 /* CSSSelectorGrammar.m in Sources */, 521 | 54FA2F71188D76AA0065B628 /* CSSClassSelector.m in Sources */, 522 | 5433BA72188D1D9E006C5F59 /* CSSTypeSelector.m in Sources */, 523 | 54FA2F79188D826F0065B628 /* CSSIDSelector.m in Sources */, 524 | 5433BA6F188D1940006C5F59 /* CSSNamedSelector.m in Sources */, 525 | 5419722F188FB97E004240B4 /* CSSSelectorXPathVisitor.m in Sources */, 526 | 54FA2F74188D7C650065B628 /* CSSSelectorToXPathConverter.m in Sources */, 527 | 5433BA66188D1808006C5F59 /* CSSUniversalSelector.m in Sources */, 528 | 54D41BAA188E7A9D00D8521A /* CSSPseudoClass.m in Sources */, 529 | 540AA35C187BC5F60012AA44 /* IGAppDelegate.m in Sources */, 530 | 54BC925B188E736000443230 /* CSSSelectors.m in Sources */, 531 | 5433BA70188D1949006C5F59 /* CSSBaseSelector.m in Sources */, 532 | 540AA358187BC5F60012AA44 /* main.m in Sources */, 533 | 54FA2F7D188D867F0065B628 /* CSSSelectorAttribute.m in Sources */, 534 | 54FA2F80188D88BA0065B628 /* CSSSelectorAttributeOperator.m in Sources */, 535 | 54FA2F84188D8F610065B628 /* CSSSelectorSequence.m in Sources */, 536 | ); 537 | runOnlyForDeploymentPostprocessing = 0; 538 | }; 539 | 540AA368187BC5F70012AA44 /* Sources */ = { 540 | isa = PBXSourcesBuildPhase; 541 | buildActionMask = 2147483647; 542 | files = ( 543 | 54FA2F76188D7CDD0065B628 /* CSSToXPathConverterSpec.m in Sources */, 544 | 54197231188FBAF0004240B4 /* CSSSelectorXPathVisitorSpec.m in Sources */, 545 | 5433BA5B188D0D71006C5F59 /* CSSSelectorTokeniserSpec.m in Sources */, 546 | 5433BA63188D1629006C5F59 /* CSSSelectorParserSpec.m in Sources */, 547 | ); 548 | runOnlyForDeploymentPostprocessing = 0; 549 | }; 550 | /* End PBXSourcesBuildPhase section */ 551 | 552 | /* Begin PBXTargetDependency section */ 553 | 540AA372187BC5F70012AA44 /* PBXTargetDependency */ = { 554 | isa = PBXTargetDependency; 555 | target = 540AA347187BC5F60012AA44 /* CSSSelectorConverter */; 556 | targetProxy = 540AA371187BC5F70012AA44 /* PBXContainerItemProxy */; 557 | }; 558 | /* End PBXTargetDependency section */ 559 | 560 | /* Begin PBXVariantGroup section */ 561 | 540AA354187BC5F60012AA44 /* InfoPlist.strings */ = { 562 | isa = PBXVariantGroup; 563 | children = ( 564 | 540AA355187BC5F60012AA44 /* en */, 565 | ); 566 | name = InfoPlist.strings; 567 | sourceTree = ""; 568 | }; 569 | 540AA35D187BC5F60012AA44 /* Main.storyboard */ = { 570 | isa = PBXVariantGroup; 571 | children = ( 572 | 540AA35E187BC5F60012AA44 /* Base */, 573 | ); 574 | name = Main.storyboard; 575 | sourceTree = ""; 576 | }; 577 | 540AA376187BC5F70012AA44 /* InfoPlist.strings */ = { 578 | isa = PBXVariantGroup; 579 | children = ( 580 | 540AA377187BC5F70012AA44 /* en */, 581 | ); 582 | name = InfoPlist.strings; 583 | sourceTree = ""; 584 | }; 585 | /* End PBXVariantGroup section */ 586 | 587 | /* Begin XCBuildConfiguration section */ 588 | 540AA37B187BC5F70012AA44 /* Debug */ = { 589 | isa = XCBuildConfiguration; 590 | buildSettings = { 591 | ALWAYS_SEARCH_USER_PATHS = NO; 592 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 593 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 594 | CLANG_CXX_LIBRARY = "libc++"; 595 | CLANG_ENABLE_MODULES = YES; 596 | CLANG_ENABLE_OBJC_ARC = YES; 597 | CLANG_WARN_BOOL_CONVERSION = YES; 598 | CLANG_WARN_CONSTANT_CONVERSION = YES; 599 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 600 | CLANG_WARN_EMPTY_BODY = YES; 601 | CLANG_WARN_ENUM_CONVERSION = YES; 602 | CLANG_WARN_INT_CONVERSION = YES; 603 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 604 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 605 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 606 | COPY_PHASE_STRIP = NO; 607 | GCC_C_LANGUAGE_STANDARD = gnu99; 608 | GCC_DYNAMIC_NO_PIC = NO; 609 | GCC_OPTIMIZATION_LEVEL = 0; 610 | GCC_PREPROCESSOR_DEFINITIONS = ( 611 | "DEBUG=1", 612 | "$(inherited)", 613 | ); 614 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 615 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 616 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 617 | GCC_WARN_UNDECLARED_SELECTOR = YES; 618 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 619 | GCC_WARN_UNUSED_FUNCTION = YES; 620 | GCC_WARN_UNUSED_VARIABLE = YES; 621 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 622 | ONLY_ACTIVE_ARCH = YES; 623 | SDKROOT = iphoneos; 624 | }; 625 | name = Debug; 626 | }; 627 | 540AA37C187BC5F70012AA44 /* Release */ = { 628 | isa = XCBuildConfiguration; 629 | buildSettings = { 630 | ALWAYS_SEARCH_USER_PATHS = NO; 631 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 632 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 633 | CLANG_CXX_LIBRARY = "libc++"; 634 | CLANG_ENABLE_MODULES = YES; 635 | CLANG_ENABLE_OBJC_ARC = YES; 636 | CLANG_WARN_BOOL_CONVERSION = YES; 637 | CLANG_WARN_CONSTANT_CONVERSION = YES; 638 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 639 | CLANG_WARN_EMPTY_BODY = YES; 640 | CLANG_WARN_ENUM_CONVERSION = YES; 641 | CLANG_WARN_INT_CONVERSION = YES; 642 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 643 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 644 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 645 | COPY_PHASE_STRIP = YES; 646 | ENABLE_NS_ASSERTIONS = NO; 647 | GCC_C_LANGUAGE_STANDARD = gnu99; 648 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 649 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 650 | GCC_WARN_UNDECLARED_SELECTOR = YES; 651 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 652 | GCC_WARN_UNUSED_FUNCTION = YES; 653 | GCC_WARN_UNUSED_VARIABLE = YES; 654 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 655 | SDKROOT = iphoneos; 656 | VALIDATE_PRODUCT = YES; 657 | }; 658 | name = Release; 659 | }; 660 | 540AA37E187BC5F70012AA44 /* Debug */ = { 661 | isa = XCBuildConfiguration; 662 | baseConfigurationReference = 48679CA62B498976F68DA0ED /* Pods.debug.xcconfig */; 663 | buildSettings = { 664 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 665 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 666 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 667 | GCC_PREFIX_HEADER = "CSSSelectorConverter/CSSSelectorConverter-Prefix.pch"; 668 | HEADER_SEARCH_PATHS = "$(inherited)"; 669 | INFOPLIST_FILE = "CSSSelectorConverter/CSSSelectorConverter-Info.plist"; 670 | PRODUCT_NAME = "$(TARGET_NAME)"; 671 | WRAPPER_EXTENSION = app; 672 | }; 673 | name = Debug; 674 | }; 675 | 540AA37F187BC5F70012AA44 /* Release */ = { 676 | isa = XCBuildConfiguration; 677 | baseConfigurationReference = 4654C27EDB914CB3303D3F76 /* Pods.release.xcconfig */; 678 | buildSettings = { 679 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 680 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 681 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 682 | GCC_PREFIX_HEADER = "CSSSelectorConverter/CSSSelectorConverter-Prefix.pch"; 683 | HEADER_SEARCH_PATHS = "$(inherited)"; 684 | INFOPLIST_FILE = "CSSSelectorConverter/CSSSelectorConverter-Info.plist"; 685 | PRODUCT_NAME = "$(TARGET_NAME)"; 686 | WRAPPER_EXTENSION = app; 687 | }; 688 | name = Release; 689 | }; 690 | 540AA381187BC5F70012AA44 /* Debug */ = { 691 | isa = XCBuildConfiguration; 692 | baseConfigurationReference = 31A43E848921BC4A334A76A7 /* Pods-CSSSelectorConverterTests.debug.xcconfig */; 693 | buildSettings = { 694 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 695 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CSSSelectorConverter.app/CSSSelectorConverter"; 696 | FRAMEWORK_SEARCH_PATHS = ( 697 | "$(SDKROOT)/Developer/Library/Frameworks", 698 | "$(inherited)", 699 | "$(DEVELOPER_FRAMEWORKS_DIR)", 700 | ); 701 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 702 | GCC_PREFIX_HEADER = "CSSSelectorConverter/CSSSelectorConverter-Prefix.pch"; 703 | GCC_PREPROCESSOR_DEFINITIONS = ( 704 | "DEBUG=1", 705 | "$(inherited)", 706 | ); 707 | HEADER_SEARCH_PATHS = ( 708 | "$(inherited)", 709 | "vendor/CoreParse/CoreParse/**", 710 | ); 711 | INFOPLIST_FILE = "CSSSelectorConverterTests/CSSSelectorConverterTests-Info.plist"; 712 | PRODUCT_NAME = "$(TARGET_NAME)"; 713 | TEST_HOST = "$(BUNDLE_LOADER)"; 714 | WRAPPER_EXTENSION = xctest; 715 | }; 716 | name = Debug; 717 | }; 718 | 540AA382187BC5F70012AA44 /* Release */ = { 719 | isa = XCBuildConfiguration; 720 | baseConfigurationReference = 2FA369A0A3C034B1BA4E570B /* Pods-CSSSelectorConverterTests.release.xcconfig */; 721 | buildSettings = { 722 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 723 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CSSSelectorConverter.app/CSSSelectorConverter"; 724 | FRAMEWORK_SEARCH_PATHS = ( 725 | "$(SDKROOT)/Developer/Library/Frameworks", 726 | "$(inherited)", 727 | "$(DEVELOPER_FRAMEWORKS_DIR)", 728 | ); 729 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 730 | GCC_PREFIX_HEADER = "CSSSelectorConverter/CSSSelectorConverter-Prefix.pch"; 731 | HEADER_SEARCH_PATHS = ( 732 | "$(inherited)", 733 | "vendor/CoreParse/CoreParse/**", 734 | ); 735 | INFOPLIST_FILE = "CSSSelectorConverterTests/CSSSelectorConverterTests-Info.plist"; 736 | PRODUCT_NAME = "$(TARGET_NAME)"; 737 | TEST_HOST = "$(BUNDLE_LOADER)"; 738 | WRAPPER_EXTENSION = xctest; 739 | }; 740 | name = Release; 741 | }; 742 | /* End XCBuildConfiguration section */ 743 | 744 | /* Begin XCConfigurationList section */ 745 | 540AA343187BC5F60012AA44 /* Build configuration list for PBXProject "CSSSelectorConverter" */ = { 746 | isa = XCConfigurationList; 747 | buildConfigurations = ( 748 | 540AA37B187BC5F70012AA44 /* Debug */, 749 | 540AA37C187BC5F70012AA44 /* Release */, 750 | ); 751 | defaultConfigurationIsVisible = 0; 752 | defaultConfigurationName = Release; 753 | }; 754 | 540AA37D187BC5F70012AA44 /* Build configuration list for PBXNativeTarget "CSSSelectorConverter" */ = { 755 | isa = XCConfigurationList; 756 | buildConfigurations = ( 757 | 540AA37E187BC5F70012AA44 /* Debug */, 758 | 540AA37F187BC5F70012AA44 /* Release */, 759 | ); 760 | defaultConfigurationIsVisible = 0; 761 | defaultConfigurationName = Release; 762 | }; 763 | 540AA380187BC5F70012AA44 /* Build configuration list for PBXNativeTarget "CSSSelectorConverterTests" */ = { 764 | isa = XCConfigurationList; 765 | buildConfigurations = ( 766 | 540AA381187BC5F70012AA44 /* Debug */, 767 | 540AA382187BC5F70012AA44 /* Release */, 768 | ); 769 | defaultConfigurationIsVisible = 0; 770 | defaultConfigurationName = Release; 771 | }; 772 | /* End XCConfigurationList section */ 773 | }; 774 | rootObject = 540AA340187BC5F60012AA44 /* Project object */; 775 | } 776 | --------------------------------------------------------------------------------