2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.connect.netconf.util;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.FluentIterable;
16 import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.collect.Iterables;
19 import com.google.common.collect.Lists;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.concurrent.ConcurrentHashMap;
29 import javax.xml.transform.dom.DOMSource;
30 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
31 import org.opendaylight.yangtools.concepts.Identifiable;
32 import org.opendaylight.yangtools.yang.common.QName;
33 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
40 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
45 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
47 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
48 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
50 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
52 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
53 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
54 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
56 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
57 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
58 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
63 * Transforms an instance of yang instance identifier to a filter like structure in normalized node format. Can be also used to nest the edit-config rpc content.
64 * For each argument of the id, a specific normalized node is created to ensure schema context conformance.
66 public abstract class InstanceIdToNodes<T extends PathArgument> implements Identifiable<T> {
68 private final T identifier;
71 public T getIdentifier() {
75 protected InstanceIdToNodes(final T identifier) {
76 this.identifier = identifier;
79 abstract InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException;
81 public abstract NormalizedNode<?, ?> create(YangInstanceIdentifier legacyData, Optional<NormalizedNode<?, ?>> deepestChild, Optional<ModifyAction> operation);
83 private static abstract class SimpleTypeNormalization<T extends PathArgument> extends InstanceIdToNodes<T> {
85 protected SimpleTypeNormalization(final T identifier) {
90 public NormalizedNode<?, ?> create(final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> deepestChild, final Optional<ModifyAction> operation) {
92 final PathArgument pathArgument = Iterables.get(id.getPathArguments(), 0);
93 final NormalizedNodeAttrBuilder<? extends PathArgument, Object, ? extends NormalizedNode<? extends PathArgument, Object>> builder = getBuilder(pathArgument);
95 if(deepestChild.isPresent()) {
96 builder.withValue(deepestChild.get().getValue());
99 addModifyOpIfPresent(operation, builder);
100 return builder.build();
103 protected abstract NormalizedNodeAttrBuilder<? extends PathArgument, Object, ? extends NormalizedNode<? extends PathArgument, Object>> getBuilder(PathArgument node);
106 public InstanceIdToNodes<?> getChild(final PathArgument child) {
112 public void addModifyOpIfPresent(final Optional<ModifyAction> operation, final AttributesBuilder<?> builder) {
113 if(operation.isPresent()) {
114 builder.withAttributes(Collections.singletonMap(NetconfMessageTransformUtil.NETCONF_OPERATION_QNAME, NetconfMessageTransformUtil.modifyOperationToXmlString(operation.get())));
118 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
120 protected LeafNormalization(final LeafSchemaNode potential) {
121 super(new NodeIdentifier(potential.getQName()));
125 protected NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> getBuilder(final PathArgument node) {
126 return Builders.leafBuilder().withNodeIdentifier(getIdentifier());
130 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
132 public LeafListEntryNormalization(final LeafListSchemaNode potential) {
133 super(new NodeWithValue(potential.getQName(), null));
137 protected NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> getBuilder(final PathArgument node) {
138 Preconditions.checkArgument(node instanceof NodeWithValue);
139 return Builders.leafSetEntryBuilder().withNodeIdentifier((NodeWithValue) node).withValue(((NodeWithValue) node).getValue());
144 private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
145 InstanceIdToNodes<T> {
147 protected CompositeNodeNormalizationOperation(final T identifier) {
152 @SuppressWarnings("unchecked")
153 public final NormalizedNode<?, ?> create(final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> lastChild, final Optional<ModifyAction> operation) {
155 final Iterator<PathArgument> iterator = id.getPathArguments().iterator();
156 final PathArgument legacyData = iterator.next();
158 if (!isMixin(this) && getIdentifier().getNodeType() != null) {
159 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
160 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
162 final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
164 if (iterator.hasNext()) {
165 final PathArgument childPath = iterator.next();
166 final InstanceIdToNodes childOp = getChildOperation(childPath);
168 final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(id.getPathArguments(), 1));
169 builder.addChild(childOp.create(childId, lastChild, operation));
171 if(lastChild.isPresent()) {
172 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
174 if(operation.isPresent()) {
175 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
176 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
180 return builder.build();
183 private InstanceIdToNodes getChildOperation(final PathArgument childPath) {
184 final InstanceIdToNodes childOp;
186 childOp = getChild(childPath);
187 } catch (final DataNormalizationException e) {
188 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
190 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
194 @SuppressWarnings("rawtypes")
195 protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
198 static boolean isMixin(final InstanceIdToNodes<?> op) {
199 return op instanceof MixinNormalizationOp;
202 private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
203 CompositeNodeNormalizationOperation<T> {
205 private final DataNodeContainer schema;
206 private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
208 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
210 this.schema = schema;
211 this.byArg = new ConcurrentHashMap<>();
215 public InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException {
216 InstanceIdToNodes<?> potential = byArg.get(child);
217 if (potential != null) {
220 potential = fromLocalSchema(child);
221 return register(potential);
224 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) throws DataNormalizationException {
225 if (child instanceof AugmentationIdentifier) {
226 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
229 return fromSchemaAndQNameChecked(schema, child.getNodeType());
232 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
233 if (potential != null) {
234 byArg.put(potential.getIdentifier(), potential);
240 private static final class ListItemNormalization extends
241 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
243 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
244 super(identifier, schema);
248 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument currentArg) {
249 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
250 .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
251 for (final Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
252 builder.addChild(Builders.leafBuilder()
254 .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
262 private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
264 protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
265 super(new NodeIdentifier(schema.getQName()), schema);
269 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
270 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
275 private static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
277 protected ContainerTransformation(final ContainerSchemaNode schema) {
278 super(new NodeIdentifier(schema.getQName()), schema);
282 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
283 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
288 * Marker interface for Mixin nodes normalization operations
290 private interface MixinNormalizationOp {}
293 private static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
296 public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
301 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
302 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
306 private static class UnorderedLeafListMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
308 private final InstanceIdToNodes<?> innerOp;
310 public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
311 super(new NodeIdentifier(potential.getQName()));
312 innerOp = new LeafListEntryNormalization(potential);
316 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
317 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
321 public InstanceIdToNodes<?> getChild(final PathArgument child) {
322 if (child instanceof NodeWithValue) {
329 private static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> implements MixinNormalizationOp {
331 public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
333 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
337 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
338 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
342 private static class UnorderedMapMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
344 private final ListItemNormalization innerNode;
346 public UnorderedMapMixinNormalization(final ListSchemaNode list) {
347 super(new NodeIdentifier(list.getQName()));
348 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
349 Collections.<QName, Object>emptyMap()), list);
353 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
354 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
358 public InstanceIdToNodes<?> getChild(final PathArgument child) {
359 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
366 private static class UnkeyedListMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
368 private final UnkeyedListItemNormalization innerNode;
370 public UnkeyedListMixinNormalization(final ListSchemaNode list) {
371 super(new NodeIdentifier(list.getQName()));
372 this.innerNode = new UnkeyedListItemNormalization(list);
376 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
377 return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier());
381 public InstanceIdToNodes<?> getChild(final PathArgument child) {
382 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
390 private static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
392 public OrderedMapMixinNormalization(final ListSchemaNode list) {
397 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
398 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
403 private static class ChoiceNodeNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
405 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
407 protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
408 super(new NodeIdentifier(schema.getQName()));
409 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
411 for (final ChoiceCaseNode caze : schema.getCases()) {
412 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
413 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
414 byArgBuilder.put(childOp.getIdentifier(), childOp);
417 byArg = byArgBuilder.build();
421 public InstanceIdToNodes<?> getChild(final PathArgument child) {
422 return byArg.get(child);
426 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
427 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
431 private static class AnyXmlNormalization extends InstanceIdToNodes<NodeIdentifier> {
433 protected AnyXmlNormalization(final AnyXmlSchemaNode schema) {
434 super(new NodeIdentifier(schema.getQName()));
438 public InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException {
443 public NormalizedNode<?, ?> create(final YangInstanceIdentifier legacyData, final Optional<NormalizedNode<?, ?>> deepestChild, final Optional<ModifyAction> operation) {
444 if(deepestChild.isPresent()) {
445 Preconditions.checkState(deepestChild instanceof AnyXmlNode);
446 final NormalizedNodeAttrBuilder<NodeIdentifier, DOMSource, AnyXmlNode> anyXmlBuilder =
447 Builders.anyXmlBuilder().withNodeIdentifier(getIdentifier()).withValue(((AnyXmlNode) deepestChild).getValue());
448 addModifyOpIfPresent(operation, anyXmlBuilder);
449 return anyXmlBuilder.build();
452 final NormalizedNodeAttrBuilder<NodeIdentifier, DOMSource, AnyXmlNode> builder =
453 Builders.anyXmlBuilder().withNodeIdentifier(getIdentifier());
454 addModifyOpIfPresent(operation, builder);
455 return builder.build();
460 private static Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent, final QName child) {
461 DataSchemaNode potential = parent.getDataChildByName(child);
462 if (potential == null) {
463 final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
464 parent.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
465 potential = findChoice(choices, child);
467 return Optional.fromNullable(potential);
470 private static InstanceIdToNodes<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) throws DataNormalizationException {
471 final Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
472 if (!potential.isPresent()) {
473 throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema, schema.getChildNodes()));
476 final DataSchemaNode result = potential.get();
477 // We try to look up if this node was added by augmentation
478 if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
479 return fromAugmentation(schema, (AugmentationTarget) schema, result);
481 return fromDataSchemaNode(result);
484 private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
485 final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices, final QName child) {
486 org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
488 for (final org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
489 for (final ChoiceCaseNode caze : choice.getCases()) {
490 if (findChildSchemaNode(caze, child).isPresent()) {
491 foundChoice = choice;
499 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
500 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
501 for (final DataSchemaNode child : augmentation.getChildNodes()) {
502 potentialChildren.add(child.getQName());
504 return new AugmentationIdentifier(potentialChildren.build());
507 private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
508 final Set<DataSchemaNode> children = new HashSet<>();
509 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
510 children.add(schema.getDataChildByName(augNode.getQName()));
512 return new NodeContainerProxy(null, children);
516 * Returns a SchemaPathUtil for provided child node
518 * If supplied child is added by Augmentation this operation returns
519 * a SchemaPathUtil for augmentation,
520 * otherwise returns a SchemaPathUtil for child as
521 * call for {@link #fromDataSchemaNode(org.opendaylight.yangtools.yang.model.api.DataSchemaNode)}.
523 private static InstanceIdToNodes<?> fromAugmentation(final DataNodeContainer parent,
524 final AugmentationTarget parentAug, final DataSchemaNode child) {
525 AugmentationSchema augmentation = null;
526 for (final AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
527 final DataSchemaNode potential = aug.getDataChildByName(child.getQName());
528 if (potential != null) {
534 if (augmentation != null) {
535 return new AugmentationNormalization(augmentation, parent);
537 return fromDataSchemaNode(child);
541 private static InstanceIdToNodes<?> fromDataSchemaNode(final DataSchemaNode potential) {
542 if (potential instanceof ContainerSchemaNode) {
543 return new ContainerTransformation((ContainerSchemaNode) potential);
544 } else if (potential instanceof ListSchemaNode) {
545 return fromListSchemaNode((ListSchemaNode) potential);
546 } else if (potential instanceof LeafSchemaNode) {
547 return new LeafNormalization((LeafSchemaNode) potential);
548 } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
549 return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
550 } else if (potential instanceof LeafListSchemaNode) {
551 return fromLeafListSchemaNode((LeafListSchemaNode) potential);
552 } else if (potential instanceof AnyXmlSchemaNode) {
553 return new AnyXmlNormalization((AnyXmlSchemaNode) potential);
558 private static InstanceIdToNodes<?> fromListSchemaNode(final ListSchemaNode potential) {
559 final List<QName> keyDefinition = potential.getKeyDefinition();
560 if (keyDefinition == null || keyDefinition.isEmpty()) {
561 return new UnkeyedListMixinNormalization(potential);
563 if (potential.isUserOrdered()) {
564 return new OrderedMapMixinNormalization(potential);
566 return new UnorderedMapMixinNormalization(potential);
569 private static InstanceIdToNodes<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
570 if (potential.isUserOrdered()) {
571 return new OrderedLeafListMixinNormalization(potential);
573 return new UnorderedLeafListMixinNormalization(potential);
576 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id) {
577 return serialize(ctx, id, Optional.<NormalizedNode<?, ?>>absent(), Optional.<ModifyAction>absent());
580 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id, final NormalizedNode<?, ?> deepestElement) {
581 return serialize(ctx, id, Optional.<NormalizedNode<?, ?>>of(deepestElement), Optional.<ModifyAction>absent());
584 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> deepestElement, final Optional<ModifyAction> operation) {
585 Preconditions.checkNotNull(ctx);
586 Preconditions.checkNotNull(id);
587 final PathArgument topLevelElement = id.getPathArguments().iterator().next();
588 final DataSchemaNode dataChildByName = ctx.getDataChildByName(topLevelElement.getNodeType());
589 Preconditions.checkNotNull(dataChildByName, "Cannot find %s node in schema context. Instance identifier has to start from root", topLevelElement);
591 final InstanceIdToNodes<?> instanceIdToNodes = fromSchemaAndQNameChecked(ctx, topLevelElement.getNodeType());
592 return instanceIdToNodes.create(id, deepestElement, operation);
593 } catch (final DataNormalizationException e) {
594 throw new IllegalArgumentException("Unable to serialize: " + id, e);