1package gojsonld 2 3// /** 4// * A container object to maintain state relating to JsonLdOptions and the 5// * current Context, and push these into the relevant algorithms in 6// * JsonLdProcessor as necessary. 7// * 8// * @author tristan 9// */ 10// public class JsonLdApi { 11 12// private final Logger log = LoggerFactory.getLogger(this.getClass()); 13 14// JsonLdOptions opts; 15// Object value = null; 16// Context context = null; 17 18// /** 19// * Constructs an empty JsonLdApi object using the default JsonLdOptions, and 20// * without initialization. 21// */ 22// public JsonLdApi() { 23// this(new JsonLdOptions("")); 24// } 25 26// /** 27// * Constructs a JsonLdApi object using the given object as the initial 28// * JSON-LD object, and the given JsonLdOptions. 29// * 30// * @param input 31// * The initial JSON-LD object. 32// * @param opts 33// * The JsonLdOptions to use. 34// * @throws JsonLdError 35// * If there is an error initializing using the object and 36// * options. 37// */ 38// public JsonLdApi(Object input, JsonLdOptions opts) throws JsonLdError { 39// this(opts); 40// initialize(input, null); 41// } 42 43// /** 44// * Constructs a JsonLdApi object using the given object as the initial 45// * JSON-LD object, the given context, and the given JsonLdOptions. 46// * 47// * @param input 48// * The initial JSON-LD object. 49// * @param context 50// * The initial context. 51// * @param opts 52// * The JsonLdOptions to use. 53// * @throws JsonLdError 54// * If there is an error initializing using the object and 55// * options. 56// */ 57// public JsonLdApi(Object input, Object context, JsonLdOptions opts) throws JsonLdError { 58// this(opts); 59// initialize(input, null); 60// } 61 62// /** 63// * Constructs an empty JsonLdApi object using the given JsonLdOptions, and 64// * without initialization. <br> 65// * If the JsonLdOptions parameter is null, then the default options are 66// * used. 67// * 68// * @param opts 69// * The JsonLdOptions to use. 70// */ 71// public JsonLdApi(JsonLdOptions opts) { 72// if (opts == null) { 73// opts = new JsonLdOptions(""); 74// } else { 75// this.opts = opts; 76// } 77// } 78 79// /** 80// * Initializes this object by cloning the input object using 81// * {@link JsonLdUtils#clone(Object)}, and by parsing the context using 82// * {@link Context#parse(Object)}. 83// * 84// * @param input 85// * The initial object, which is to be cloned and used in 86// * operations. 87// * @param context 88// * The context object, which is to be parsed and used in 89// * operations. 90// * @throws JsonLdError 91// * If there was an error cloning the object, or in parsing the 92// * context. 93// */ 94// private void initialize(Object input, Object context) throws JsonLdError { 95// if (input instanceof List || input instanceof Map) { 96// this.value = JsonLdUtils.clone(input); 97// } 98// // TODO: string/IO input 99// this.context = new Context(opts); 100// if (context != null) { 101// this.context = this.context.parse(context); 102// } 103// } 104 105// /*** 106// * ____ _ _ _ _ _ _ / ___|___ _ __ ___ _ __ __ _ ___| |_ / \ | | __ _ ___ _ 107// * __(_) |_| |__ _ __ ___ | | / _ \| '_ ` _ \| '_ \ / _` |/ __| __| / _ \ | 108// * |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | |__| (_) | | | | | | |_) | (_| 109// * | (__| |_ / ___ \| | (_| | (_) | | | | |_| | | | | | | | | \____\___/|_| 110// * |_| |_| .__/ \__,_|\___|\__| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| 111// * |_| |_| |___/ 112// */ 113 114// /** 115// * Compaction Algorithm 116// * 117// * http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm 118// * 119// * @param activeCtx 120// * The Active Context 121// * @param activeProperty 122// * The Active Property 123// * @param element 124// * The current element 125// * @param compactArrays 126// * True to compact arrays. 127// * @return The compacted JSON-LD object. 128// * @throws JsonLdError 129// * If there was an error during compaction. 130// */ 131// public Object compact(Context activeCtx, String activeProperty, Object element, 132// boolean compactArrays) throws JsonLdError { 133// // 2) 134// if (element instanceof List) { 135// // 2.1) 136// final List<Object> result = new ArrayList<Object>(); 137// // 2.2) 138// for (final Object item : (List<Object>) element) { 139// // 2.2.1) 140// final Object compactedItem = compact(activeCtx, activeProperty, item, compactArrays); 141// // 2.2.2) 142// if (compactedItem != null) { 143// result.add(compactedItem); 144// } 145// } 146// // 2.3) 147// if (compactArrays && result.size() == 1 148// && activeCtx.getContainer(activeProperty) == null) { 149// return result.get(0); 150// } 151// // 2.4) 152// return result; 153// } 154 155// // 3) 156// if (element instanceof Map) { 157// // access helper 158// final Map<String, Object> elem = (Map<String, Object>) element; 159 160// // 4 161// if (elem.containsKey("@value") || elem.containsKey("@id")) { 162// final Object compactedValue = activeCtx.compactValue(activeProperty, elem); 163// if (!(compactedValue instanceof Map || compactedValue instanceof List)) { 164// return compactedValue; 165// } 166// } 167// // 5) 168// final boolean insideReverse = ("@reverse".equals(activeProperty)); 169 170// // 6) 171// final Map<String, Object> result = new LinkedHashMap<String, Object>(); 172// // 7) 173// final List<String> keys = new ArrayList<String>(elem.keySet()); 174// Collections.sort(keys); 175// for (final String expandedProperty : keys) { 176// final Object expandedValue = elem.get(expandedProperty); 177 178// // 7.1) 179// if ("@id".equals(expandedProperty) || "@type".equals(expandedProperty)) { 180// Object compactedValue; 181 182// // 7.1.1) 183// if (expandedValue instanceof String) { 184// compactedValue = activeCtx.compactIri((String) expandedValue, 185// "@type".equals(expandedProperty)); 186// } 187// // 7.1.2) 188// else { 189// final List<String> types = new ArrayList<String>(); 190// // 7.1.2.2) 191// for (final String expandedType : (List<String>) expandedValue) { 192// types.add(activeCtx.compactIri(expandedType, true)); 193// } 194// // 7.1.2.3) 195// if (types.size() == 1) { 196// compactedValue = types.get(0); 197// } else { 198// compactedValue = types; 199// } 200// } 201 202// // 7.1.3) 203// final String alias = activeCtx.compactIri(expandedProperty, true); 204// // 7.1.4) 205// result.put(alias, compactedValue); 206// continue; 207// // TODO: old add value code, see if it's still relevant? 208// // addValue(rval, alias, compactedValue, 209// // isArray(compactedValue) 210// // && ((List<Object>) expandedValue).size() == 0); 211// } 212 213// // 7.2) 214// if ("@reverse".equals(expandedProperty)) { 215// // 7.2.1) 216// final Map<String, Object> compactedValue = (Map<String, Object>) compact( 217// activeCtx, "@reverse", expandedValue, compactArrays); 218 219// // 7.2.2) 220// // Note: Must create a new set to avoid modifying the set we 221// // are iterating over 222// for (final String property : new HashSet<String>(compactedValue.keySet())) { 223// final Object value = compactedValue.get(property); 224// // 7.2.2.1) 225// if (activeCtx.isReverseProperty(property)) { 226// // 7.2.2.1.1) 227// if (("@set".equals(activeCtx.getContainer(property)) || !compactArrays) 228// && !(value instanceof List)) { 229// final List<Object> tmp = new ArrayList<Object>(); 230// tmp.add(value); 231// result.put(property, tmp); 232// } 233// // 7.2.2.1.2) 234// if (!result.containsKey(property)) { 235// result.put(property, value); 236// } 237// // 7.2.2.1.3) 238// else { 239// if (!(result.get(property) instanceof List)) { 240// final List<Object> tmp = new ArrayList<Object>(); 241// tmp.add(result.put(property, tmp)); 242// } 243// if (value instanceof List) { 244// ((List<Object>) result.get(property)) 245// .addAll((List<Object>) value); 246// } else { 247// ((List<Object>) result.get(property)).add(value); 248// } 249// } 250// // 7.2.2.1.4) 251// compactedValue.remove(property); 252// } 253// } 254// // 7.2.3) 255// if (!compactedValue.isEmpty()) { 256// // 7.2.3.1) 257// final String alias = activeCtx.compactIri("@reverse", true); 258// // 7.2.3.2) 259// result.put(alias, compactedValue); 260// } 261// // 7.2.4) 262// continue; 263// } 264 265// // 7.3) 266// if ("@index".equals(expandedProperty) 267// && "@index".equals(activeCtx.getContainer(activeProperty))) { 268// continue; 269// } 270// // 7.4) 271// else if ("@index".equals(expandedProperty) || "@value".equals(expandedProperty) 272// || "@language".equals(expandedProperty)) { 273// // 7.4.1) 274// final String alias = activeCtx.compactIri(expandedProperty, true); 275// // 7.4.2) 276// result.put(alias, expandedValue); 277// continue; 278// } 279 280// // NOTE: expanded value must be an array due to expansion 281// // algorithm. 282 283// // 7.5) 284// if (((List<Object>) expandedValue).size() == 0) { 285// // 7.5.1) 286// final String itemActiveProperty = activeCtx.compactIri(expandedProperty, 287// expandedValue, true, insideReverse); 288// // 7.5.2) 289// if (!result.containsKey(itemActiveProperty)) { 290// result.put(itemActiveProperty, new ArrayList<Object>()); 291// } else { 292// final Object value = result.get(itemActiveProperty); 293// if (!(value instanceof List)) { 294// final List<Object> tmp = new ArrayList<Object>(); 295// tmp.add(value); 296// result.put(itemActiveProperty, tmp); 297// } 298// } 299// } 300 301// // 7.6) 302// for (final Object expandedItem : (List<Object>) expandedValue) { 303// // 7.6.1) 304// final String itemActiveProperty = activeCtx.compactIri(expandedProperty, 305// expandedItem, true, insideReverse); 306// // 7.6.2) 307// final String container = activeCtx.getContainer(itemActiveProperty); 308 309// // get @list value if appropriate 310// final boolean isList = (expandedItem instanceof Map && ((Map<String, Object>) expandedItem) 311// .containsKey("@list")); 312// Object list = null; 313// if (isList) { 314// list = ((Map<String, Object>) expandedItem).get("@list"); 315// } 316 317// // 7.6.3) 318// Object compactedItem = compact(activeCtx, itemActiveProperty, isList ? list 319// : expandedItem, compactArrays); 320 321// // 7.6.4) 322// if (isList) { 323// // 7.6.4.1) 324// if (!(compactedItem instanceof List)) { 325// final List<Object> tmp = new ArrayList<Object>(); 326// tmp.add(compactedItem); 327// compactedItem = tmp; 328// } 329// // 7.6.4.2) 330// if (!"@list".equals(container)) { 331// // 7.6.4.2.1) 332// final Map<String, Object> wrapper = new LinkedHashMap<String, Object>(); 333// // TODO: SPEC: no mention of vocab = true 334// wrapper.put(activeCtx.compactIri("@list", true), compactedItem); 335// compactedItem = wrapper; 336 337// // 7.6.4.2.2) 338// if (((Map<String, Object>) expandedItem).containsKey("@index")) { 339// ((Map<String, Object>) compactedItem).put( 340// // TODO: SPEC: no mention of vocab = 341// // true 342// activeCtx.compactIri("@index", true), 343// ((Map<String, Object>) expandedItem).get("@index")); 344// } 345// } 346// // 7.6.4.3) 347// else if (result.containsKey(itemActiveProperty)) { 348// throw new JsonLdError(Error.COMPACTION_TO_LIST_OF_LISTS, 349// "There cannot be two list objects associated with an active property that has a container mapping"); 350// } 351// } 352 353// // 7.6.5) 354// if ("@language".equals(container) || "@index".equals(container)) { 355// // 7.6.5.1) 356// Map<String, Object> mapObject; 357// if (result.containsKey(itemActiveProperty)) { 358// mapObject = (Map<String, Object>) result.get(itemActiveProperty); 359// } else { 360// mapObject = new LinkedHashMap<String, Object>(); 361// result.put(itemActiveProperty, mapObject); 362// } 363 364// // 7.6.5.2) 365// if ("@language".equals(container) 366// && (compactedItem instanceof Map && ((Map<String, Object>) compactedItem) 367// .containsKey("@value"))) { 368// compactedItem = ((Map<String, Object>) compactedItem).get("@value"); 369// } 370 371// // 7.6.5.3) 372// final String mapKey = (String) ((Map<String, Object>) expandedItem) 373// .get(container); 374// // 7.6.5.4) 375// if (!mapObject.containsKey(mapKey)) { 376// mapObject.put(mapKey, compactedItem); 377// } else { 378// List<Object> tmp; 379// if (!(mapObject.get(mapKey) instanceof List)) { 380// tmp = new ArrayList<Object>(); 381// tmp.add(mapObject.put(mapKey, tmp)); 382// } else { 383// tmp = (List<Object>) mapObject.get(mapKey); 384// } 385// tmp.add(compactedItem); 386// } 387// } 388// // 7.6.6) 389// else { 390// // 7.6.6.1) 391// final Boolean check = (!compactArrays || "@set".equals(container) 392// || "@list".equals(container) || "@list".equals(expandedProperty) || "@graph" 393// .equals(expandedProperty)) 394// && (!(compactedItem instanceof List)); 395// if (check) { 396// final List<Object> tmp = new ArrayList<Object>(); 397// tmp.add(compactedItem); 398// compactedItem = tmp; 399// } 400// // 7.6.6.2) 401// if (!result.containsKey(itemActiveProperty)) { 402// result.put(itemActiveProperty, compactedItem); 403// } else { 404// if (!(result.get(itemActiveProperty) instanceof List)) { 405// final List<Object> tmp = new ArrayList<Object>(); 406// tmp.add(result.put(itemActiveProperty, tmp)); 407// } 408// if (compactedItem instanceof List) { 409// ((List<Object>) result.get(itemActiveProperty)) 410// .addAll((List<Object>) compactedItem); 411// } else { 412// ((List<Object>) result.get(itemActiveProperty)).add(compactedItem); 413// } 414// } 415 416// } 417// } 418// } 419// // 8) 420// return result; 421// } 422 423// // 2) 424// return element; 425// } 426 427// /** 428// * Compaction Algorithm 429// * 430// * http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm 431// * 432// * @param activeCtx 433// * The Active Context 434// * @param activeProperty 435// * The Active Property 436// * @param element 437// * The current element 438// * @return The compacted JSON-LD object. 439// * @throws JsonLdError 440// * If there was an error during compaction. 441// */ 442// public Object compact(Context activeCtx, String activeProperty, Object element) 443// throws JsonLdError { 444// return compact(activeCtx, activeProperty, element, true); 445// } 446 447// /*** 448// * _____ _ _ _ _ _ _ | ____|_ ___ __ __ _ _ __ __| | / \ | | __ _ ___ _ 449// * __(_) |_| |__ _ __ ___ | _| \ \/ / '_ \ / _` | '_ \ / _` | / _ \ | |/ _` 450// * |/ _ \| '__| | __| '_ \| '_ ` _ \ | |___ > <| |_) | (_| | | | | (_| | / 451// * ___ \| | (_| | (_) | | | | |_| | | | | | | | | |_____/_/\_\ .__/ \__,_|_| 452// * |_|\__,_| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| |_| |___/ 453// */ 454 455// /** 456// * Expansion Algorithm 457// * 458// * http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm 459// * 460// * @param activeCtx 461// * The Active Context 462// * @param activeProperty 463// * The Active Property 464// * @param element 465// * The current element 466// * @return The expanded JSON-LD object. 467// * @throws JsonLdError 468// * If there was an error during expansion. 469// */ 470// public Object expand(Context activeCtx, String activeProperty, Object element) 471// throws JsonLdError { 472// // 1) 473// if (element == null) { 474// return null; 475// } 476 477// // 3) 478// if (element instanceof List) { 479// // 3.1) 480// final List<Object> result = new ArrayList<Object>(); 481// // 3.2) 482// for (final Object item : (List<Object>) element) { 483// // 3.2.1) 484// final Object v = expand(activeCtx, activeProperty, item); 485// // 3.2.2) 486// if (("@list".equals(activeProperty) || "@list".equals(activeCtx 487// .getContainer(activeProperty))) 488// && (v instanceof List || (v instanceof Map && ((Map<String, Object>) v) 489// .containsKey("@list")))) { 490// throw new JsonLdError(Error.LIST_OF_LISTS, "lists of lists are not permitted."); 491// } 492// // 3.2.3) 493// else if (v != null) { 494// if (v instanceof List) { 495// result.addAll((Collection<? extends Object>) v); 496// } else { 497// result.add(v); 498// } 499// } 500// } 501// // 3.3) 502// return result; 503// } 504// // 4) 505// else if (element instanceof Map) { 506// // access helper 507// final Map<String, Object> elem = (Map<String, Object>) element; 508// // 5) 509// if (elem.containsKey("@context")) { 510// activeCtx = activeCtx.parse(elem.get("@context")); 511// } 512// // 6) 513// Map<String, Object> result = new LinkedHashMap<String, Object>(); 514// // 7) 515// final List<String> keys = new ArrayList<String>(elem.keySet()); 516// Collections.sort(keys); 517// for (final String key : keys) { 518// final Object value = elem.get(key); 519// // 7.1) 520// if (key.equals("@context")) { 521// continue; 522// } 523// // 7.2) 524// final String expandedProperty = activeCtx.expandIri(key, false, true, null, null); 525// Object expandedValue = null; 526// // 7.3) 527// if (expandedProperty == null 528// || (!expandedProperty.contains(":") && !isKeyword(expandedProperty))) { 529// continue; 530// } 531// // 7.4) 532// if (isKeyword(expandedProperty)) { 533// // 7.4.1) 534// if ("@reverse".equals(activeProperty)) { 535// throw new JsonLdError(Error.INVALID_REVERSE_PROPERTY_MAP, 536// "a keyword cannot be used as a @reverse propery"); 537// } 538// // 7.4.2) 539// if (result.containsKey(expandedProperty)) { 540// throw new JsonLdError(Error.COLLIDING_KEYWORDS, expandedProperty 541// + " already exists in result"); 542// } 543// // 7.4.3) 544// if ("@id".equals(expandedProperty)) { 545// if (!(value instanceof String)) { 546// throw new JsonLdError(Error.INVALID_ID_VALUE, 547// "value of @id must be a string"); 548// } 549// expandedValue = activeCtx 550// .expandIri((String) value, true, false, null, null); 551// } 552// // 7.4.4) 553// else if ("@type".equals(expandedProperty)) { 554// if (value instanceof List) { 555// expandedValue = new ArrayList<String>(); 556// for (final Object v : (List) value) { 557// if (!(v instanceof String)) { 558// throw new JsonLdError(Error.INVALID_TYPE_VALUE, 559// "@type value must be a string or array of strings"); 560// } 561// ((List<String>) expandedValue).add(activeCtx.expandIri((String) v, 562// true, true, null, null)); 563// } 564// } else if (value instanceof String) { 565// expandedValue = activeCtx.expandIri((String) value, true, true, null, 566// null); 567// } 568// // TODO: SPEC: no mention of empty map check 569// else if (value instanceof Map) { 570// if (((Map<String, Object>) value).size() != 0) { 571// throw new JsonLdError(Error.INVALID_TYPE_VALUE, 572// "@type value must be a an empty object for framing"); 573// } 574// expandedValue = value; 575// } else { 576// throw new JsonLdError(Error.INVALID_TYPE_VALUE, 577// "@type value must be a string or array of strings"); 578// } 579// } 580// // 7.4.5) 581// else if ("@graph".equals(expandedProperty)) { 582// expandedValue = expand(activeCtx, "@graph", value); 583// } 584// // 7.4.6) 585// else if ("@value".equals(expandedProperty)) { 586// if (value != null && (value instanceof Map || value instanceof List)) { 587// throw new JsonLdError(Error.INVALID_VALUE_OBJECT_VALUE, "value of " 588// + expandedProperty + " must be a scalar or null"); 589// } 590// expandedValue = value; 591// if (expandedValue == null) { 592// result.put("@value", null); 593// continue; 594// } 595// } 596// // 7.4.7) 597// else if ("@language".equals(expandedProperty)) { 598// if (!(value instanceof String)) { 599// throw new JsonLdError(Error.INVALID_LANGUAGE_TAGGED_STRING, "Value of " 600// + expandedProperty + " must be a string"); 601// } 602// expandedValue = ((String) value).toLowerCase(); 603// } 604// // 7.4.8) 605// else if ("@index".equals(expandedProperty)) { 606// if (!(value instanceof String)) { 607// throw new JsonLdError(Error.INVALID_INDEX_VALUE, "Value of " 608// + expandedProperty + " must be a string"); 609// } 610// expandedValue = value; 611// } 612// // 7.4.9) 613// else if ("@list".equals(expandedProperty)) { 614// // 7.4.9.1) 615// if (activeProperty == null || "@graph".equals(activeProperty)) { 616// continue; 617// } 618// // 7.4.9.2) 619// expandedValue = expand(activeCtx, activeProperty, value); 620 621// // NOTE: step not in the spec yet 622// if (!(expandedValue instanceof List)) { 623// final List<Object> tmp = new ArrayList<Object>(); 624// tmp.add(expandedValue); 625// expandedValue = tmp; 626// } 627 628// // 7.4.9.3) 629// for (final Object o : (List<Object>) expandedValue) { 630// if (o instanceof Map && ((Map<String, Object>) o).containsKey("@list")) { 631// throw new JsonLdError(Error.LIST_OF_LISTS, 632// "A list may not contain another list"); 633// } 634// } 635// } 636// // 7.4.10) 637// else if ("@set".equals(expandedProperty)) { 638// expandedValue = expand(activeCtx, activeProperty, value); 639// } 640// // 7.4.11) 641// else if ("@reverse".equals(expandedProperty)) { 642// if (!(value instanceof Map)) { 643// throw new JsonLdError(Error.INVALID_REVERSE_VALUE, 644// "@reverse value must be an object"); 645// } 646// // 7.4.11.1) 647// expandedValue = expand(activeCtx, "@reverse", value); 648// // NOTE: algorithm assumes the result is a map 649// // 7.4.11.2) 650// if (((Map<String, Object>) expandedValue).containsKey("@reverse")) { 651// final Map<String, Object> reverse = (Map<String, Object>) ((Map<String, Object>) expandedValue) 652// .get("@reverse"); 653// for (final String property : reverse.keySet()) { 654// final Object item = reverse.get(property); 655// // 7.4.11.2.1) 656// if (!result.containsKey(property)) { 657// result.put(property, new ArrayList<Object>()); 658// } 659// // 7.4.11.2.2) 660// if (item instanceof List) { 661// ((List<Object>) result.get(property)) 662// .addAll((List<Object>) item); 663// } else { 664// ((List<Object>) result.get(property)).add(item); 665// } 666// } 667// } 668// // 7.4.11.3) 669// if (((Map<String, Object>) expandedValue).size() > (((Map<String, Object>) expandedValue) 670// .containsKey("@reverse") ? 1 : 0)) { 671// // 7.4.11.3.1) 672// if (!result.containsKey("@reverse")) { 673// result.put("@reverse", new LinkedHashMap<String, Object>()); 674// } 675// // 7.4.11.3.2) 676// final Map<String, Object> reverseMap = (Map<String, Object>) result 677// .get("@reverse"); 678// // 7.4.11.3.3) 679// for (final String property : ((Map<String, Object>) expandedValue) 680// .keySet()) { 681// if ("@reverse".equals(property)) { 682// continue; 683// } 684// // 7.4.11.3.3.1) 685// final List<Object> items = (List<Object>) ((Map<String, Object>) expandedValue) 686// .get(property); 687// for (final Object item : items) { 688// // 7.4.11.3.3.1.1) 689// if (item instanceof Map 690// && (((Map<String, Object>) item).containsKey("@value") || ((Map<String, Object>) item) 691// .containsKey("@list"))) { 692// throw new JsonLdError(Error.INVALID_REVERSE_PROPERTY_VALUE); 693// } 694// // 7.4.11.3.3.1.2) 695// if (!reverseMap.containsKey(property)) { 696// reverseMap.put(property, new ArrayList<Object>()); 697// } 698// // 7.4.11.3.3.1.3) 699// ((List<Object>) reverseMap.get(property)).add(item); 700// } 701// } 702// } 703// // 7.4.11.4) 704// continue; 705// } 706// // TODO: SPEC no mention of @explicit etc in spec 707// else if ("@explicit".equals(expandedProperty) 708// || "@default".equals(expandedProperty) 709// || "@embed".equals(expandedProperty) 710// || "@embedChildren".equals(expandedProperty) 711// || "@omitDefault".equals(expandedProperty)) { 712// expandedValue = expand(activeCtx, expandedProperty, value); 713// } 714// // 7.4.12) 715// if (expandedValue != null) { 716// result.put(expandedProperty, expandedValue); 717// } 718// // 7.4.13) 719// continue; 720// } 721// // 7.5 722// else if ("@language".equals(activeCtx.getContainer(key)) && value instanceof Map) { 723// // 7.5.1) 724// expandedValue = new ArrayList<Object>(); 725// // 7.5.2) 726// for (final String language : ((Map<String, Object>) value).keySet()) { 727// Object languageValue = ((Map<String, Object>) value).get(language); 728// // 7.5.2.1) 729// if (!(languageValue instanceof List)) { 730// final Object tmp = languageValue; 731// languageValue = new ArrayList<Object>(); 732// ((List<Object>) languageValue).add(tmp); 733// } 734// // 7.5.2.2) 735// for (final Object item : (List<Object>) languageValue) { 736// // 7.5.2.2.1) 737// if (!(item instanceof String)) { 738// throw new JsonLdError(Error.INVALID_LANGUAGE_MAP_VALUE, "Expected " 739// + item.toString() + " to be a string"); 740// } 741// // 7.5.2.2.2) 742// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 743// tmp.put("@value", item); 744// tmp.put("@language", language.toLowerCase()); 745// ((List<Object>) expandedValue).add(tmp); 746// } 747// } 748// } 749// // 7.6) 750// else if ("@index".equals(activeCtx.getContainer(key)) && value instanceof Map) { 751// // 7.6.1) 752// expandedValue = new ArrayList<Object>(); 753// // 7.6.2) 754// final List<String> indexKeys = new ArrayList<String>( 755// ((Map<String, Object>) value).keySet()); 756// Collections.sort(indexKeys); 757// for (final String index : indexKeys) { 758// Object indexValue = ((Map<String, Object>) value).get(index); 759// // 7.6.2.1) 760// if (!(indexValue instanceof List)) { 761// final Object tmp = indexValue; 762// indexValue = new ArrayList<Object>(); 763// ((List<Object>) indexValue).add(tmp); 764// } 765// // 7.6.2.2) 766// indexValue = expand(activeCtx, key, indexValue); 767// // 7.6.2.3) 768// for (final Map<String, Object> item : (List<Map<String, Object>>) indexValue) { 769// // 7.6.2.3.1) 770// if (!item.containsKey("@index")) { 771// item.put("@index", index); 772// } 773// // 7.6.2.3.2) 774// ((List<Object>) expandedValue).add(item); 775// } 776// } 777// } 778// // 7.7) 779// else { 780// expandedValue = expand(activeCtx, key, value); 781// } 782// // 7.8) 783// if (expandedValue == null) { 784// continue; 785// } 786// // 7.9) 787// if ("@list".equals(activeCtx.getContainer(key))) { 788// if (!(expandedValue instanceof Map) 789// || !((Map<String, Object>) expandedValue).containsKey("@list")) { 790// Object tmp = expandedValue; 791// if (!(tmp instanceof List)) { 792// tmp = new ArrayList<Object>(); 793// ((List<Object>) tmp).add(expandedValue); 794// } 795// expandedValue = new LinkedHashMap<String, Object>(); 796// ((Map<String, Object>) expandedValue).put("@list", tmp); 797// } 798// } 799// // 7.10) 800// if (activeCtx.isReverseProperty(key)) { 801// // 7.10.1) 802// if (!result.containsKey("@reverse")) { 803// result.put("@reverse", new LinkedHashMap<String, Object>()); 804// } 805// // 7.10.2) 806// final Map<String, Object> reverseMap = (Map<String, Object>) result 807// .get("@reverse"); 808// // 7.10.3) 809// if (!(expandedValue instanceof List)) { 810// final Object tmp = expandedValue; 811// expandedValue = new ArrayList<Object>(); 812// ((List<Object>) expandedValue).add(tmp); 813// } 814// // 7.10.4) 815// for (final Object item : (List<Object>) expandedValue) { 816// // 7.10.4.1) 817// if (item instanceof Map 818// && (((Map<String, Object>) item).containsKey("@value") || ((Map<String, Object>) item) 819// .containsKey("@list"))) { 820// throw new JsonLdError(Error.INVALID_REVERSE_PROPERTY_VALUE); 821// } 822// // 7.10.4.2) 823// if (!reverseMap.containsKey(expandedProperty)) { 824// reverseMap.put(expandedProperty, new ArrayList<Object>()); 825// } 826// // 7.10.4.3) 827// if (item instanceof List) { 828// ((List<Object>) reverseMap.get(expandedProperty)) 829// .addAll((List<Object>) item); 830// } else { 831// ((List<Object>) reverseMap.get(expandedProperty)).add(item); 832// } 833// } 834// } 835// // 7.11) 836// else { 837// // 7.11.1) 838// if (!result.containsKey(expandedProperty)) { 839// result.put(expandedProperty, new ArrayList<Object>()); 840// } 841// // 7.11.2) 842// if (expandedValue instanceof List) { 843// ((List<Object>) result.get(expandedProperty)) 844// .addAll((List<Object>) expandedValue); 845// } else { 846// ((List<Object>) result.get(expandedProperty)).add(expandedValue); 847// } 848// } 849// } 850// // 8) 851// if (result.containsKey("@value")) { 852// // 8.1) 853// // TODO: is this method faster than just using containsKey for 854// // each? 855// final Set<String> keySet = new HashSet(result.keySet()); 856// keySet.remove("@value"); 857// keySet.remove("@index"); 858// final boolean langremoved = keySet.remove("@language"); 859// final boolean typeremoved = keySet.remove("@type"); 860// if ((langremoved && typeremoved) || !keySet.isEmpty()) { 861// throw new JsonLdError(Error.INVALID_VALUE_OBJECT, 862// "value object has unknown keys"); 863// } 864// // 8.2) 865// final Object rval = result.get("@value"); 866// if (rval == null) { 867// // nothing else is possible with result if we set it to 868// // null, so simply return it 869// return null; 870// } 871// // 8.3) 872// if (!(rval instanceof String) && result.containsKey("@language")) { 873// throw new JsonLdError(Error.INVALID_LANGUAGE_TAGGED_VALUE, 874// "when @language is used, @value must be a string"); 875// } 876// // 8.4) 877// else if (result.containsKey("@type")) { 878// // TODO: is this enough for "is an IRI" 879// if (!(result.get("@type") instanceof String) 880// || ((String) result.get("@type")).startsWith("_:") 881// || !((String) result.get("@type")).contains(":")) { 882// throw new JsonLdError(Error.INVALID_TYPED_VALUE, 883// "value of @type must be an IRI"); 884// } 885// } 886// } 887// // 9) 888// else if (result.containsKey("@type")) { 889// final Object rtype = result.get("@type"); 890// if (!(rtype instanceof List)) { 891// final List<Object> tmp = new ArrayList<Object>(); 892// tmp.add(rtype); 893// result.put("@type", tmp); 894// } 895// } 896// // 10) 897// else if (result.containsKey("@set") || result.containsKey("@list")) { 898// // 10.1) 899// if (result.size() > (result.containsKey("@index") ? 2 : 1)) { 900// throw new JsonLdError(Error.INVALID_SET_OR_LIST_OBJECT, 901// "@set or @list may only contain @index"); 902// } 903// // 10.2) 904// if (result.containsKey("@set")) { 905// // result becomes an array here, thus the remaining checks 906// // will never be true from here on 907// // so simply return the value rather than have to make 908// // result an object and cast it with every 909// // other use in the function. 910// return result.get("@set"); 911// } 912// } 913// // 11) 914// if (result.containsKey("@language") && result.size() == 1) { 915// result = null; 916// } 917// // 12) 918// if (activeProperty == null || "@graph".equals(activeProperty)) { 919// // 12.1) 920// if (result != null 921// && (result.size() == 0 || result.containsKey("@value") || result 922// .containsKey("@list"))) { 923// result = null; 924// } 925// // 12.2) 926// else if (result != null && result.containsKey("@id") && result.size() == 1) { 927// result = null; 928// } 929// } 930// // 13) 931// return result; 932// } 933// // 2) If element is a scalar 934// else { 935// // 2.1) 936// if (activeProperty == null || "@graph".equals(activeProperty)) { 937// return null; 938// } 939// return activeCtx.expandValue(activeProperty, element); 940// } 941// } 942 943// * 944// * Expansion Algorithm 945// * 946// * http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm 947// * 948// * @param activeCtx 949// * The Active Context 950// * @param element 951// * The current element 952// * @return The expanded JSON-LD object. 953// * @throws JsonLdError 954// * If there was an error during expansion. 955 956// public Object expand(Context activeCtx, Object element) throws JsonLdError { 957// return expand(activeCtx, null, element); 958// } 959 960// /*** 961// * _____ _ _ _ _ _ _ _ _ | ___| | __ _| |_| |_ ___ _ __ / \ | | __ _ ___ _ 962// * __(_) |_| |__ _ __ ___ | |_ | |/ _` | __| __/ _ \ '_ \ / _ \ | |/ _` |/ _ 963// * \| '__| | __| '_ \| '_ ` _ \ | _| | | (_| | |_| || __/ | | | / ___ \| | 964// * (_| | (_) | | | | |_| | | | | | | | | |_| |_|\__,_|\__|\__\___|_| |_| /_/ 965// * \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| |___/ 966// */ 967 968// void generateNodeMap(Object element, Map<String, Object> nodeMap) throws JsonLdError { 969// generateNodeMap(element, nodeMap, "@default", null, null, null); 970// } 971 972// void generateNodeMap(Object element, Map<String, Object> nodeMap, String activeGraph) 973// throws JsonLdError { 974// generateNodeMap(element, nodeMap, activeGraph, null, null, null); 975// } 976 977// void generateNodeMap(Object element, Map<String, Object> nodeMap, String activeGraph, 978// Object activeSubject, String activeProperty, Map<String, Object> list) 979// throws JsonLdError { 980// // 1) 981// if (element instanceof List) { 982// // 1.1) 983// for (final Object item : (List<Object>) element) { 984// generateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, list); 985// } 986// return; 987// } 988 989// // for convenience 990// final Map<String, Object> elem = (Map<String, Object>) element; 991 992// // 2) 993// if (!nodeMap.containsKey(activeGraph)) { 994// nodeMap.put(activeGraph, new LinkedHashMap<String, Object>()); 995// } 996// final Map<String, Object> graph = (Map<String, Object>) nodeMap.get(activeGraph); 997// Map<String, Object> node = (Map<String, Object>) (activeSubject == null ? null : graph 998// .get(activeSubject)); 999 1000// // 3) 1001// if (elem.containsKey("@type")) { 1002// // 3.1) 1003// List<String> oldTypes; 1004// final List<String> newTypes = new ArrayList<String>(); 1005// if (elem.get("@type") instanceof List) { 1006// oldTypes = (List<String>) elem.get("@type"); 1007// } else { 1008// oldTypes = new ArrayList<String>(); 1009// oldTypes.add((String) elem.get("@type")); 1010// } 1011// for (final String item : oldTypes) { 1012// if (item.startsWith("_:")) { 1013// newTypes.add(generateBlankNodeIdentifier(item)); 1014// } else { 1015// newTypes.add(item); 1016// } 1017// } 1018// if (elem.get("@type") instanceof List) { 1019// elem.put("@type", newTypes); 1020// } else { 1021// elem.put("@type", newTypes.get(0)); 1022// } 1023// } 1024 1025// // 4) 1026// if (elem.containsKey("@value")) { 1027// // 4.1) 1028// if (list == null) { 1029// JsonLdUtils.mergeValue(node, activeProperty, elem); 1030// } 1031// // 4.2) 1032// else { 1033// JsonLdUtils.mergeValue(list, "@list", elem); 1034// } 1035// } 1036 1037// // 5) 1038// else if (elem.containsKey("@list")) { 1039// // 5.1) 1040// final Map<String, Object> result = new LinkedHashMap<String, Object>(); 1041// result.put("@list", new ArrayList<Object>()); 1042// // 5.2) 1043// // for (final Object item : (List<Object>) elem.get("@list")) { 1044// // generateNodeMap(item, nodeMap, activeGraph, activeSubject, 1045// // activeProperty, result); 1046// // } 1047// generateNodeMap(elem.get("@list"), nodeMap, activeGraph, activeSubject, activeProperty, 1048// result); 1049// // 5.3) 1050// JsonLdUtils.mergeValue(node, activeProperty, result); 1051// } 1052 1053// // 6) 1054// else { 1055// // 6.1) 1056// String id = (String) elem.remove("@id"); 1057// if (id != null) { 1058// if (id.startsWith("_:")) { 1059// id = generateBlankNodeIdentifier(id); 1060// } 1061// } 1062// // 6.2) 1063// else { 1064// id = generateBlankNodeIdentifier(null); 1065// } 1066// // 6.3) 1067// if (!graph.containsKey(id)) { 1068// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 1069// tmp.put("@id", id); 1070// graph.put(id, tmp); 1071// } 1072// // 6.4) TODO: SPEC this line is asked for by the spec, but it breaks 1073// // various tests 1074// // node = (Map<String, Object>) graph.get(id); 1075// // 6.5) 1076// if (activeSubject instanceof Map) { 1077// // 6.5.1) 1078// JsonLdUtils.mergeValue((Map<String, Object>) graph.get(id), activeProperty, 1079// activeSubject); 1080// } 1081// // 6.6) 1082// else if (activeProperty != null) { 1083// final Map<String, Object> reference = new LinkedHashMap<String, Object>(); 1084// reference.put("@id", id); 1085// // 6.6.2) 1086// if (list == null) { 1087// // 6.6.2.1+2) 1088// JsonLdUtils.mergeValue(node, activeProperty, reference); 1089// } 1090// // 6.6.3) TODO: SPEC says to add ELEMENT to @list member, should 1091// // be REFERENCE 1092// else { 1093// JsonLdUtils.mergeValue(list, "@list", reference); 1094// } 1095// } 1096// // TODO: SPEC this is removed in the spec now, but it's still needed 1097// // (see 6.4) 1098// node = (Map<String, Object>) graph.get(id); 1099// // 6.7) 1100// if (elem.containsKey("@type")) { 1101// for (final Object type : (List<Object>) elem.remove("@type")) { 1102// JsonLdUtils.mergeValue(node, "@type", type); 1103// } 1104// } 1105// // 6.8) 1106// if (elem.containsKey("@index")) { 1107// final Object elemIndex = elem.remove("@index"); 1108// if (node.containsKey("@index")) { 1109// if (!JsonLdUtils.deepCompare(node.get("@index"), elemIndex)) { 1110// throw new JsonLdError(Error.CONFLICTING_INDEXES); 1111// } 1112// } else { 1113// node.put("@index", elemIndex); 1114// } 1115// } 1116// // 6.9) 1117// if (elem.containsKey("@reverse")) { 1118// // 6.9.1) 1119// final Map<String, Object> referencedNode = new LinkedHashMap<String, Object>(); 1120// referencedNode.put("@id", id); 1121// // 6.9.2+6.9.4) 1122// final Map<String, Object> reverseMap = (Map<String, Object>) elem 1123// .remove("@reverse"); 1124// // 6.9.3) 1125// for (final String property : reverseMap.keySet()) { 1126// final List<Object> values = (List<Object>) reverseMap.get(property); 1127// // 6.9.3.1) 1128// for (final Object value : values) { 1129// // 6.9.3.1.1) 1130// generateNodeMap(value, nodeMap, activeGraph, referencedNode, property, null); 1131// } 1132// } 1133// } 1134// // 6.10) 1135// if (elem.containsKey("@graph")) { 1136// generateNodeMap(elem.remove("@graph"), nodeMap, id, null, null, null); 1137// } 1138// // 6.11) 1139// final List<String> keys = new ArrayList<String>(elem.keySet()); 1140// Collections.sort(keys); 1141// for (String property : keys) { 1142// final Object value = elem.get(property); 1143// // 6.11.1) 1144// if (property.startsWith("_:")) { 1145// property = generateBlankNodeIdentifier(property); 1146// } 1147// // 6.11.2) 1148// if (!node.containsKey(property)) { 1149// node.put(property, new ArrayList<Object>()); 1150// } 1151// // 6.11.3) 1152// generateNodeMap(value, nodeMap, activeGraph, id, property, null); 1153// } 1154// } 1155// } 1156 1157// /** 1158// * Blank Node identifier map specified in: 1159// * 1160// * http://www.w3.org/TR/json-ld-api/#generate-blank-node-identifier 1161// */ 1162// private final Map<String, String> blankNodeIdentifierMap = new LinkedHashMap<String, String>(); 1163 1164// /** 1165// * Counter specified in: 1166// * 1167// * http://www.w3.org/TR/json-ld-api/#generate-blank-node-identifier 1168// */ 1169// private int blankNodeCounter = 0; 1170 1171// /** 1172// * Generates a blank node identifier for the given key using the algorithm 1173// * specified in: 1174// * 1175// * http://www.w3.org/TR/json-ld-api/#generate-blank-node-identifier 1176// * 1177// * @param id 1178// * The id, or null to generate a fresh, unused, blank node 1179// * identifier. 1180// * @return A blank node identifier based on id if it was not null, or a 1181// * fresh, unused, blank node identifier if it was null. 1182// */ 1183// String generateBlankNodeIdentifier(String id) { 1184// if (id != null && blankNodeIdentifierMap.containsKey(id)) { 1185// return blankNodeIdentifierMap.get(id); 1186// } 1187// final String bnid = "_:b" + blankNodeCounter++; 1188// if (id != null) { 1189// blankNodeIdentifierMap.put(id, bnid); 1190// } 1191// return bnid; 1192// } 1193 1194// /** 1195// * Generates a fresh, unused, blank node identifier using the algorithm 1196// * specified in: 1197// * 1198// * http://www.w3.org/TR/json-ld-api/#generate-blank-node-identifier 1199// * 1200// * @return A fresh, unused, blank node identifier. 1201// */ 1202// String generateBlankNodeIdentifier() { 1203// return generateBlankNodeIdentifier(null); 1204// } 1205 1206// /*** 1207// * _____ _ _ _ _ _ _ | ___| __ __ _ _ __ ___ (_)_ __ __ _ / \ | | __ _ ___ _ 1208// * __(_) |_| |__ _ __ ___ | |_ | '__/ _` | '_ ` _ \| | '_ \ / _` | / _ \ | 1209// * |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | _|| | | (_| | | | | | | | | | | 1210// * (_| | / ___ \| | (_| | (_) | | | | |_| | | | | | | | | |_| |_| \__,_|_| 1211// * |_| |_|_|_| |_|\__, | /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| 1212// * |___/ |___/ 1213// */ 1214 1215// private class FramingContext { 1216// public boolean embed; 1217// public boolean explicit; 1218// public boolean omitDefault; 1219 1220// public FramingContext() { 1221// embed = true; 1222// explicit = false; 1223// omitDefault = false; 1224// embeds = null; 1225// } 1226 1227// public FramingContext(JsonLdOptions opts) { 1228// this(); 1229// if (opts.getEmbed() != null) { 1230// this.embed = opts.getEmbed(); 1231// } 1232// if (opts.getExplicit() != null) { 1233// this.explicit = opts.getExplicit(); 1234// } 1235// if (opts.getOmitDefault() != null) { 1236// this.omitDefault = opts.getOmitDefault(); 1237// } 1238// } 1239 1240// public Map<String, EmbedNode> embeds = null; 1241// } 1242 1243// private class EmbedNode { 1244// public Object parent = null; 1245// public String property = null; 1246// } 1247 1248// private Map<String, Object> nodeMap; 1249 1250// /** 1251// * Performs JSON-LD <a 1252// * href="http://json-ld.org/spec/latest/json-ld-framing/">framing</a>. 1253// * 1254// * @param input 1255// * the expanded JSON-LD to frame. 1256// * @param frame 1257// * the expanded JSON-LD frame to use. 1258// * @return the framed output. 1259// * @throws JsonLdError 1260// * If the framing was not successful. 1261// */ 1262// public List<Object> frame(Object input, List<Object> frame) throws JsonLdError { 1263// // create framing state 1264// final FramingContext state = new FramingContext(this.opts); 1265 1266// // use tree map so keys are sotred by default 1267// final Map<String, Object> nodes = new TreeMap<String, Object>(); 1268// generateNodeMap(input, nodes); 1269// this.nodeMap = (Map<String, Object>) nodes.get("@default"); 1270 1271// final List<Object> framed = new ArrayList<Object>(); 1272// // NOTE: frame validation is done by the function not allowing anything 1273// // other than list to me passed 1274// frame(state, this.nodeMap, 1275// (frame != null && frame.size() > 0 ? (Map<String, Object>) frame.get(0) 1276// : new LinkedHashMap<String, Object>()), framed, null); 1277 1278// return framed; 1279// } 1280 1281// /** 1282// * Frames subjects according to the given frame. 1283// * 1284// * @param state 1285// * the current framing state. 1286// * @param subjects 1287// * the subjects to filter. 1288// * @param frame 1289// * the frame. 1290// * @param parent 1291// * the parent subject or top-level array. 1292// * @param property 1293// * the parent property, initialized to null. 1294// * @throws JsonLdError 1295// * If there was an error during framing. 1296// */ 1297// private void frame(FramingContext state, Map<String, Object> nodes, Map<String, Object> frame, 1298// Object parent, String property) throws JsonLdError { 1299 1300// // filter out subjects that match the frame 1301// final Map<String, Object> matches = filterNodes(state, nodes, frame); 1302 1303// // get flags for current frame 1304// Boolean embedOn = getFrameFlag(frame, "@embed", state.embed); 1305// final Boolean explicicOn = getFrameFlag(frame, "@explicit", state.explicit); 1306 1307// // add matches to output 1308// final List<String> ids = new ArrayList<String>(matches.keySet()); 1309// Collections.sort(ids); 1310// for (final String id : ids) { 1311// if (property == null) { 1312// state.embeds = new LinkedHashMap<String, EmbedNode>(); 1313// } 1314 1315// // start output 1316// final Map<String, Object> output = new LinkedHashMap<String, Object>(); 1317// output.put("@id", id); 1318 1319// // prepare embed meta info 1320// final EmbedNode embeddedNode = new EmbedNode(); 1321// embeddedNode.parent = parent; 1322// embeddedNode.property = property; 1323 1324// // if embed is on and there is an existing embed 1325// if (embedOn && state.embeds.containsKey(id)) { 1326// final EmbedNode existing = state.embeds.get(id); 1327// embedOn = false; 1328 1329// if (existing.parent instanceof List) { 1330// for (final Object p : (List<Object>) existing.parent) { 1331// if (JsonLdUtils.compareValues(output, p)) { 1332// embedOn = true; 1333// break; 1334// } 1335// } 1336// } 1337// // existing embed's parent is an object 1338// else { 1339// if (((Map<String, Object>) existing.parent).containsKey(existing.property)) { 1340// for (final Object v : (List<Object>) ((Map<String, Object>) existing.parent) 1341// .get(existing.property)) { 1342// if (v instanceof Map 1343// && Obj.equals(id, ((Map<String, Object>) v).get("@id"))) { 1344// embedOn = true; 1345// break; 1346// } 1347// } 1348// } 1349// } 1350 1351// // existing embed has already been added, so allow an overwrite 1352// if (embedOn) { 1353// removeEmbed(state, id); 1354// } 1355// } 1356 1357// // not embedding, add output without any other properties 1358// if (!embedOn) { 1359// addFrameOutput(state, parent, property, output); 1360// } else { 1361// // add embed meta info 1362// state.embeds.put(id, embeddedNode); 1363 1364// // iterate over subject properties 1365// final Map<String, Object> element = (Map<String, Object>) matches.get(id); 1366// List<String> props = new ArrayList<String>(element.keySet()); 1367// Collections.sort(props); 1368// for (final String prop : props) { 1369 1370// // copy keywords to output 1371// if (isKeyword(prop)) { 1372// output.put(prop, JsonLdUtils.clone(element.get(prop))); 1373// continue; 1374// } 1375 1376// // if property isn't in the frame 1377// if (!frame.containsKey(prop)) { 1378// // if explicit is off, embed values 1379// if (!explicicOn) { 1380// embedValues(state, element, prop, output); 1381// } 1382// continue; 1383// } 1384 1385// // add objects 1386// final List<Object> value = (List<Object>) element.get(prop); 1387 1388// for (final Object item : value) { 1389 1390// // recurse into list 1391// if ((item instanceof Map) 1392// && ((Map<String, Object>) item).containsKey("@list")) { 1393// // add empty list 1394// final Map<String, Object> list = new LinkedHashMap<String, Object>(); 1395// list.put("@list", new ArrayList<Object>()); 1396// addFrameOutput(state, output, prop, list); 1397 1398// // add list objects 1399// for (final Object listitem : (List<Object>) ((Map<String, Object>) item) 1400// .get("@list")) { 1401// // recurse into subject reference 1402// if (JsonLdUtils.isNodeReference(listitem)) { 1403// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 1404// final String itemid = (String) ((Map<String, Object>) listitem) 1405// .get("@id"); 1406// // TODO: nodes may need to be node_map, 1407// // which is global 1408// tmp.put(itemid, this.nodeMap.get(itemid)); 1409// frame(state, tmp, 1410// (Map<String, Object>) ((List<Object>) frame.get(prop)) 1411// .get(0), list, "@list"); 1412// } else { 1413// // include other values automatcially (TODO: 1414// // may need JsonLdUtils.clone(n)) 1415// addFrameOutput(state, list, "@list", listitem); 1416// } 1417// } 1418// } 1419 1420// // recurse into subject reference 1421// else if (JsonLdUtils.isNodeReference(item)) { 1422// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 1423// final String itemid = (String) ((Map<String, Object>) item).get("@id"); 1424// // TODO: nodes may need to be node_map, which is 1425// // global 1426// tmp.put(itemid, this.nodeMap.get(itemid)); 1427// frame(state, tmp, 1428// (Map<String, Object>) ((List<Object>) frame.get(prop)).get(0), 1429// output, prop); 1430// } else { 1431// // include other values automatically (TODO: may 1432// // need JsonLdUtils.clone(o)) 1433// addFrameOutput(state, output, prop, item); 1434// } 1435// } 1436// } 1437 1438// // handle defaults 1439// props = new ArrayList<String>(frame.keySet()); 1440// Collections.sort(props); 1441// for (final String prop : props) { 1442// // skip keywords 1443// if (isKeyword(prop)) { 1444// continue; 1445// } 1446 1447// final List<Object> pf = (List<Object>) frame.get(prop); 1448// Map<String, Object> propertyFrame = pf.size() > 0 ? (Map<String, Object>) pf 1449// .get(0) : null; 1450// if (propertyFrame == null) { 1451// propertyFrame = new LinkedHashMap<String, Object>(); 1452// } 1453// final boolean omitDefaultOn = getFrameFlag(propertyFrame, "@omitDefault", 1454// state.omitDefault); 1455// if (!omitDefaultOn && !output.containsKey(prop)) { 1456// Object def = "@null"; 1457// if (propertyFrame.containsKey("@default")) { 1458// def = JsonLdUtils.clone(propertyFrame.get("@default")); 1459// } 1460// if (!(def instanceof List)) { 1461// final List<Object> tmp = new ArrayList<Object>(); 1462// tmp.add(def); 1463// def = tmp; 1464// } 1465// final Map<String, Object> tmp1 = new LinkedHashMap<String, Object>(); 1466// tmp1.put("@preserve", def); 1467// final List<Object> tmp2 = new ArrayList<Object>(); 1468// tmp2.add(tmp1); 1469// output.put(prop, tmp2); 1470// } 1471// } 1472 1473// // add output to parent 1474// addFrameOutput(state, parent, property, output); 1475// } 1476// } 1477// } 1478 1479// private Boolean getFrameFlag(Map<String, Object> frame, String name, boolean thedefault) { 1480// Object value = frame.get(name); 1481// if (value instanceof List) { 1482// if (((List<Object>) value).size() > 0) { 1483// value = ((List<Object>) value).get(0); 1484// } 1485// } 1486// if (value instanceof Map && ((Map<String, Object>) value).containsKey("@value")) { 1487// value = ((Map<String, Object>) value).get("@value"); 1488// } 1489// if (value instanceof Boolean) { 1490// return (Boolean) value; 1491// } 1492// return thedefault; 1493// } 1494 1495// /** 1496// * Removes an existing embed. 1497// * 1498// * @param state 1499// * the current framing state. 1500// * @param id 1501// * the @id of the embed to remove. 1502// */ 1503// private static void removeEmbed(FramingContext state, String id) { 1504// // get existing embed 1505// final Map<String, EmbedNode> embeds = state.embeds; 1506// final EmbedNode embed = embeds.get(id); 1507// final Object parent = embed.parent; 1508// final String property = embed.property; 1509 1510// // create reference to replace embed 1511// final Map<String, Object> node = new LinkedHashMap<String, Object>(); 1512// node.put("@id", id); 1513 1514// // remove existing embed 1515// if (JsonLdUtils.isNode(parent)) { 1516// // replace subject with reference 1517// final List<Object> newvals = new ArrayList<Object>(); 1518// final List<Object> oldvals = (List<Object>) ((Map<String, Object>) parent) 1519// .get(property); 1520// for (final Object v : oldvals) { 1521// if (v instanceof Map && Obj.equals(((Map<String, Object>) v).get("@id"), id)) { 1522// newvals.add(node); 1523// } else { 1524// newvals.add(v); 1525// } 1526// } 1527// ((Map<String, Object>) parent).put(property, newvals); 1528// } 1529// // recursively remove dependent dangling embeds 1530// removeDependents(embeds, id); 1531// } 1532 1533// private static void removeDependents(Map<String, EmbedNode> embeds, String id) { 1534// // get embed keys as a separate array to enable deleting keys in map 1535// for (final String id_dep : embeds.keySet()) { 1536// final EmbedNode e = embeds.get(id_dep); 1537// final Object p = e.parent != null ? e.parent : new LinkedHashMap<String, Object>(); 1538// if (!(p instanceof Map)) { 1539// continue; 1540// } 1541// final String pid = (String) ((Map<String, Object>) p).get("@id"); 1542// if (Obj.equals(id, pid)) { 1543// embeds.remove(id_dep); 1544// removeDependents(embeds, id_dep); 1545// } 1546// } 1547// } 1548 1549// private Map<String, Object> filterNodes(FramingContext state, Map<String, Object> nodes, 1550// Map<String, Object> frame) throws JsonLdError { 1551// final Map<String, Object> rval = new LinkedHashMap<String, Object>(); 1552// for (final String id : nodes.keySet()) { 1553// final Map<String, Object> element = (Map<String, Object>) nodes.get(id); 1554// if (element != null && filterNode(state, element, frame)) { 1555// rval.put(id, element); 1556// } 1557// } 1558// return rval; 1559// } 1560 1561// private boolean filterNode(FramingContext state, Map<String, Object> node, 1562// Map<String, Object> frame) throws JsonLdError { 1563// final Object types = frame.get("@type"); 1564// if (types != null) { 1565// if (!(types instanceof List)) { 1566// throw new JsonLdError(Error.SYNTAX_ERROR, "frame @type must be an array"); 1567// } 1568// Object nodeTypes = node.get("@type"); 1569// if (nodeTypes == null) { 1570// nodeTypes = new ArrayList<Object>(); 1571// } else if (!(nodeTypes instanceof List)) { 1572// throw new JsonLdError(Error.SYNTAX_ERROR, "node @type must be an array"); 1573// } 1574// if (((List<Object>) types).size() == 1 && ((List<Object>) types).get(0) instanceof Map 1575// && ((Map<String, Object>) ((List<Object>) types).get(0)).size() == 0) { 1576// return !((List<Object>) nodeTypes).isEmpty(); 1577// } else { 1578// for (final Object i : (List<Object>) nodeTypes) { 1579// for (final Object j : (List<Object>) types) { 1580// if (JsonLdUtils.deepCompare(i, j)) { 1581// return true; 1582// } 1583// } 1584// } 1585// return false; 1586// } 1587// } else { 1588// for (final String key : frame.keySet()) { 1589// if ("@id".equals(key) || !isKeyword(key) && !(node.containsKey(key))) { 1590// return false; 1591// } 1592// } 1593// return true; 1594// } 1595// } 1596 1597// /** 1598// * Adds framing output to the given parent. 1599// * 1600// * @param state 1601// * the current framing state. 1602// * @param parent 1603// * the parent to add to. 1604// * @param property 1605// * the parent property. 1606// * @param output 1607// * the output to add. 1608// */ 1609// private static void addFrameOutput(FramingContext state, Object parent, String property, 1610// Object output) { 1611// if (parent instanceof Map) { 1612// List<Object> prop = (List<Object>) ((Map<String, Object>) parent).get(property); 1613// if (prop == null) { 1614// prop = new ArrayList<Object>(); 1615// ((Map<String, Object>) parent).put(property, prop); 1616// } 1617// prop.add(output); 1618// } else { 1619// ((List) parent).add(output); 1620// } 1621// } 1622 1623// /** 1624// * Embeds values for the given subject and property into the given output 1625// * during the framing algorithm. 1626// * 1627// * @param state 1628// * the current framing state. 1629// * @param element 1630// * the subject. 1631// * @param property 1632// * the property. 1633// * @param output 1634// * the output. 1635// */ 1636// private void embedValues(FramingContext state, Map<String, Object> element, String property, 1637// Object output) { 1638// // embed subject properties in output 1639// final List<Object> objects = (List<Object>) element.get(property); 1640// for (Object o : objects) { 1641// // handle subject reference 1642// if (JsonLdUtils.isNodeReference(o)) { 1643// final String sid = (String) ((Map<String, Object>) o).get("@id"); 1644 1645// // embed full subject if isn't already embedded 1646// if (!state.embeds.containsKey(sid)) { 1647// // add embed 1648// final EmbedNode embed = new EmbedNode(); 1649// embed.parent = output; 1650// embed.property = property; 1651// state.embeds.put(sid, embed); 1652 1653// // recurse into subject 1654// o = new LinkedHashMap<String, Object>(); 1655// Map<String, Object> s = (Map<String, Object>) this.nodeMap.get(sid); 1656// if (s == null) { 1657// s = new LinkedHashMap<String, Object>(); 1658// s.put("@id", sid); 1659// } 1660// for (final String prop : s.keySet()) { 1661// // copy keywords 1662// if (isKeyword(prop)) { 1663// ((Map<String, Object>) o).put(prop, JsonLdUtils.clone(s.get(prop))); 1664// continue; 1665// } 1666// embedValues(state, s, prop, o); 1667// } 1668// } 1669// addFrameOutput(state, output, property, o); 1670// } 1671// // copy non-subject value 1672// else { 1673// addFrameOutput(state, output, property, JsonLdUtils.clone(o)); 1674// } 1675// } 1676// } 1677 1678// /*** 1679// * ____ _ __ ____ ____ _____ _ _ _ _ _ / ___|___ _ ____ _____ _ __| |_ / _|_ 1680// * __ ___ _ __ ___ | _ \| _ \| ___| / \ | | __ _ ___ _ __(_) |_| |__ _ __ 1681// * ___ | | / _ \| '_ \ \ / / _ \ '__| __| | |_| '__/ _ \| '_ ` _ \ | |_) | | 1682// * | | |_ / _ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | |__| (_) | | | \ 1683// * V / __/ | | |_ | _| | | (_) | | | | | | | _ <| |_| | _| / ___ \| | (_| | 1684// * (_) | | | | |_| | | | | | | | | \____\___/|_| |_|\_/ \___|_| \__| |_| |_| 1685// * \___/|_| |_| |_| |_| \_\____/|_| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| 1686// * |_| |_| |___/ 1687// */ 1688 1689// /** 1690// * Helper class for node usages 1691// * 1692// * @author tristan 1693// */ 1694// private class UsagesNode { 1695// public UsagesNode(NodeMapNode node, String property, Map<String, Object> value) { 1696// this.node = node; 1697// this.property = property; 1698// this.value = value; 1699// } 1700 1701// public NodeMapNode node = null; 1702// public String property = null; 1703// public Map<String, Object> value = null; 1704// } 1705 1706// private class NodeMapNode extends LinkedHashMap<String, Object> { 1707// public List<UsagesNode> usages = new ArrayList(); 1708 1709// public NodeMapNode(String id) { 1710// super(); 1711// this.put("@id", id); 1712// } 1713 1714// // helper fucntion for 4.3.3 1715// public boolean isWellFormedListNode() { 1716// if (usages.size() != 1) { 1717// return false; 1718// } 1719// int keys = 0; 1720// if (containsKey(RDF_FIRST)) { 1721// keys++; 1722// if (!(get(RDF_FIRST) instanceof List && ((List<Object>) get(RDF_FIRST)).size() == 1)) { 1723// return false; 1724// } 1725// } 1726// if (containsKey(RDF_REST)) { 1727// keys++; 1728// if (!(get(RDF_REST) instanceof List && ((List<Object>) get(RDF_REST)).size() == 1)) { 1729// return false; 1730// } 1731// } 1732// if (containsKey("@type")) { 1733// keys++; 1734// if (!(get("@type") instanceof List && ((List<Object>) get("@type")).size() == 1) 1735// && RDF_LIST.equals(((List<Object>) get("@type")).get(0))) { 1736// return false; 1737// } 1738// } 1739// // TODO: SPEC: 4.3.3 has no mention of @id 1740// if (containsKey("@id")) { 1741// keys++; 1742// } 1743// if (keys < size()) { 1744// return false; 1745// } 1746// return true; 1747// } 1748 1749// // return this node without the usages variable 1750// public Map<String, Object> serialize() { 1751// return new LinkedHashMap<String, Object>(this); 1752// } 1753// } 1754 1755// /** 1756// * Converts RDF statements into JSON-LD. 1757// * 1758// * @param dataset 1759// * the RDF statements. 1760// * @return A list of JSON-LD objects found in the given dataset. 1761// * @throws JsonLdError 1762// * If there was an error during conversion from RDF to JSON-LD. 1763// */ 1764// public List<Object> fromRDF(final RDFDataset dataset) throws JsonLdError { 1765// // 1) 1766// final Map<String, NodeMapNode> defaultGraph = new LinkedHashMap<String, NodeMapNode>(); 1767// // 2) 1768// final Map<String, Map<String, NodeMapNode>> graphMap = new LinkedHashMap<String, Map<String, NodeMapNode>>(); 1769// graphMap.put("@default", defaultGraph); 1770 1771// // 3/3.1) 1772// for (final String name : dataset.graphNames()) { 1773 1774// final List<RDFDataset.Quad> graph = dataset.getQuads(name); 1775 1776// // 3.2+3.4) 1777// Map<String, NodeMapNode> nodeMap; 1778// if (!graphMap.containsKey(name)) { 1779// nodeMap = new LinkedHashMap<String, NodeMapNode>(); 1780// graphMap.put(name, nodeMap); 1781// } else { 1782// nodeMap = graphMap.get(name); 1783// } 1784 1785// // 3.3) 1786// if (!"@default".equals(name) && !Obj.contains(defaultGraph, name)) { 1787// defaultGraph.put(name, new NodeMapNode(name)); 1788// } 1789 1790// // 3.5) 1791// for (final RDFDataset.Quad triple : graph) { 1792// final String subject = triple.getSubject().getValue(); 1793// final String predicate = triple.getPredicate().getValue(); 1794// final RDFDataset.Node object = triple.getObject(); 1795 1796// // 3.5.1+3.5.2) 1797// NodeMapNode node; 1798// if (!nodeMap.containsKey(subject)) { 1799// node = new NodeMapNode(subject); 1800// nodeMap.put(subject, node); 1801// } else { 1802// node = nodeMap.get(subject); 1803// } 1804 1805// // 3.5.3) 1806// if ((object.isIRI() || object.isBlankNode()) 1807// && !nodeMap.containsKey(object.getValue())) { 1808// nodeMap.put(object.getValue(), new NodeMapNode(object.getValue())); 1809// } 1810 1811// // 3.5.4) 1812// if (RDF_TYPE.equals(predicate) && (object.isIRI() || object.isBlankNode()) 1813// && !opts.getUseRdfType()) { 1814// JsonLdUtils.mergeValue(node, "@type", object.getValue()); 1815// continue; 1816// } 1817 1818// // 3.5.5) 1819// final Map<String, Object> value = object.toObject(opts.getUseNativeTypes()); 1820 1821// // 3.5.6+7) 1822// JsonLdUtils.mergeValue(node, predicate, value); 1823 1824// // 3.5.8) 1825// if (object.isBlankNode() || object.isIRI()) { 1826// // 3.5.8.1-3) 1827// nodeMap.get(object.getValue()).usages 1828// .add(new UsagesNode(node, predicate, value)); 1829// } 1830// } 1831// } 1832 1833// // 4) 1834// for (final String name : graphMap.keySet()) { 1835// final Map<String, NodeMapNode> graph = graphMap.get(name); 1836 1837// // 4.1) 1838// if (!graph.containsKey(RDF_NIL)) { 1839// continue; 1840// } 1841 1842// // 4.2) 1843// final NodeMapNode nil = graph.get(RDF_NIL); 1844// // 4.3) 1845// for (final UsagesNode usage : nil.usages) { 1846// // 4.3.1) 1847// NodeMapNode node = usage.node; 1848// String property = usage.property; 1849// Map<String, Object> head = usage.value; 1850// // 4.3.2) 1851// final List<Object> list = new ArrayList<Object>(); 1852// final List<String> listNodes = new ArrayList<String>(); 1853// // 4.3.3) 1854// while (RDF_REST.equals(property) && node.isWellFormedListNode()) { 1855// // 4.3.3.1) 1856// list.add(((List<Object>) node.get(RDF_FIRST)).get(0)); 1857// // 4.3.3.2) 1858// listNodes.add((String) node.get("@id")); 1859// // 4.3.3.3) 1860// final UsagesNode nodeUsage = node.usages.get(0); 1861// // 4.3.3.4) 1862// node = nodeUsage.node; 1863// property = nodeUsage.property; 1864// head = nodeUsage.value; 1865// // 4.3.3.5) 1866// if (!JsonLdUtils.isBlankNode(node)) { 1867// break; 1868// } 1869// } 1870// // 4.3.4) 1871// if (RDF_FIRST.equals(property)) { 1872// // 4.3.4.1) 1873// if (RDF_NIL.equals(node.get("@id"))) { 1874// continue; 1875// } 1876// // 4.3.4.3) 1877// final String headId = (String) head.get("@id"); 1878// // 4.3.4.4-5) 1879// head = (Map<String, Object>) ((List<Object>) graph.get(headId).get(RDF_REST)) 1880// .get(0); 1881// // 4.3.4.6) 1882// list.remove(list.size() - 1); 1883// listNodes.remove(listNodes.size() - 1); 1884// } 1885// // 4.3.5) 1886// head.remove("@id"); 1887// // 4.3.6) 1888// Collections.reverse(list); 1889// // 4.3.7) 1890// head.put("@list", list); 1891// // 4.3.8) 1892// for (final String nodeId : listNodes) { 1893// graph.remove(nodeId); 1894// } 1895// } 1896// } 1897 1898// // 5) 1899// final List<Object> result = new ArrayList<Object>(); 1900// // 6) 1901// final List<String> ids = new ArrayList<String>(defaultGraph.keySet()); 1902// Collections.sort(ids); 1903// for (final String subject : ids) { 1904// final NodeMapNode node = defaultGraph.get(subject); 1905// // 6.1) 1906// if (graphMap.containsKey(subject)) { 1907// // 6.1.1) 1908// node.put("@graph", new ArrayList<Object>()); 1909// // 6.1.2) 1910// final List<String> keys = new ArrayList<String>(graphMap.get(subject).keySet()); 1911// Collections.sort(keys); 1912// for (final String s : keys) { 1913// final NodeMapNode n = graphMap.get(subject).get(s); 1914// if (n.size() == 1 && n.containsKey("@id")) { 1915// continue; 1916// } 1917// ((List<Object>) node.get("@graph")).add(n.serialize()); 1918// } 1919// } 1920// // 6.2) 1921// if (node.size() == 1 && node.containsKey("@id")) { 1922// continue; 1923// } 1924// result.add(node.serialize()); 1925// } 1926 1927// return result; 1928// } 1929 1930// /*** 1931// * ____ _ _ ____ ____ _____ _ _ _ _ _ / ___|___ _ ____ _____ _ __| |_ | |_ 1932// * ___ | _ \| _ \| ___| / \ | | __ _ ___ _ __(_) |_| |__ _ __ ___ | | / _ \| 1933// * '_ \ \ / / _ \ '__| __| | __/ _ \ | |_) | | | | |_ / _ \ | |/ _` |/ _ \| 1934// * '__| | __| '_ \| '_ ` _ \ | |__| (_) | | | \ V / __/ | | |_ | || (_) | | 1935// * _ <| |_| | _| / ___ \| | (_| | (_) | | | | |_| | | | | | | | | 1936// * \____\___/|_| |_|\_/ \___|_| \__| \__\___/ |_| \_\____/|_| /_/ \_\_|\__, 1937// * |\___/|_| |_|\__|_| |_|_| |_| |_| |___/ 1938// */ 1939 1940// /** 1941// * Adds RDF triples for each graph in the current node map to an RDF 1942// * dataset. 1943// * 1944// * @return the RDF dataset. 1945// * @throws JsonLdError 1946// * If there was an error converting from JSON-LD to RDF. 1947// */ 1948// public RDFDataset toRDF() throws JsonLdError { 1949// // TODO: make the default generateNodeMap call (i.e. without a 1950// // graphName) create and return the nodeMap 1951// final Map<String, Object> nodeMap = new LinkedHashMap<String, Object>(); 1952// nodeMap.put("@default", new LinkedHashMap<String, Object>()); 1953// generateNodeMap(this.value, nodeMap); 1954 1955// final RDFDataset dataset = new RDFDataset(this); 1956 1957// for (final String graphName : nodeMap.keySet()) { 1958// // 4.1) 1959// if (JsonLdUtils.isRelativeIri(graphName)) { 1960// continue; 1961// } 1962// final Map<String, Object> graph = (Map<String, Object>) nodeMap.get(graphName); 1963// dataset.graphToRDF(graphName, graph); 1964// } 1965 1966// return dataset; 1967// } 1968 1969// /*** 1970// * _ _ _ _ _ _ _ _ _ _ _ | \ | | ___ _ __ _ __ ___ __ _| (_)______ _| |_(_) 1971// * ___ _ __ / \ | | __ _ ___ _ __(_) |_| |__ _ __ ___ | \| |/ _ \| '__| '_ ` 1972// * _ \ / _` | | |_ / _` | __| |/ _ \| '_ \ / _ \ | |/ _` |/ _ \| '__| | __| 1973// * '_ \| '_ ` _ \ | |\ | (_) | | | | | | | | (_| | | |/ / (_| | |_| | (_) | 1974// * | | | / ___ \| | (_| | (_) | | | | |_| | | | | | | | | |_| \_|\___/|_| 1975// * |_| |_| |_|\__,_|_|_/___\__,_|\__|_|\___/|_| |_| /_/ \_\_|\__, |\___/|_| 1976// * |_|\__|_| |_|_| |_| |_| |___/ 1977// */ 1978 1979// /** 1980// * Performs RDF normalization on the given JSON-LD input. 1981// * 1982// * @param dataset 1983// * the expanded JSON-LD object to normalize. 1984// * @return The normalized JSON-LD object 1985// * @throws JsonLdError 1986// * If there was an error while normalizing. 1987// */ 1988// public Object normalize(Map<String, Object> dataset) throws JsonLdError { 1989// // create quads and map bnodes to their associated quads 1990// final List<Object> quads = new ArrayList<Object>(); 1991// final Map<String, Object> bnodes = new LinkedHashMap<String, Object>(); 1992// for (String graphName : dataset.keySet()) { 1993// final List<Map<String, Object>> triples = (List<Map<String, Object>>) dataset 1994// .get(graphName); 1995// if ("@default".equals(graphName)) { 1996// graphName = null; 1997// } 1998// for (final Map<String, Object> quad : triples) { 1999// if (graphName != null) { 2000// if (graphName.indexOf("_:") == 0) { 2001// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 2002// tmp.put("type", "blank node"); 2003// tmp.put("value", graphName); 2004// quad.put("name", tmp); 2005// } else { 2006// final Map<String, Object> tmp = new LinkedHashMap<String, Object>(); 2007// tmp.put("type", "IRI"); 2008// tmp.put("value", graphName); 2009// quad.put("name", tmp); 2010// } 2011// } 2012// quads.add(quad); 2013 2014// final String[] attrs = new String[] { "subject", "object", "name" }; 2015// for (final String attr : attrs) { 2016// if (quad.containsKey(attr) 2017// && "blank node".equals(((Map<String, Object>) quad.get(attr)) 2018// .get("type"))) { 2019// final String id = (String) ((Map<String, Object>) quad.get(attr)) 2020// .get("value"); 2021// if (!bnodes.containsKey(id)) { 2022// bnodes.put(id, new LinkedHashMap<String, List<Object>>() { 2023// { 2024// put("quads", new ArrayList<Object>()); 2025// } 2026// }); 2027// } 2028// ((List<Object>) ((Map<String, Object>) bnodes.get(id)).get("quads")) 2029// .add(quad); 2030// } 2031// } 2032// } 2033// } 2034 2035// // mapping complete, start canonical naming 2036// final NormalizeUtils normalizeUtils = new NormalizeUtils(quads, bnodes, new UniqueNamer( 2037// "_:c14n"), opts); 2038// return normalizeUtils.hashBlankNodes(bnodes.keySet()); 2039// } 2040 2041// } 2042