0
# XML Types
1
2
XML-aware collaborative types for structured document editing with DOM integration. These types enable collaborative editing of XML/HTML documents while maintaining proper document structure and supporting real-time synchronization.
3
4
## Capabilities
5
6
### YXmlFragment
7
8
Container type for XML elements and text nodes, providing the foundation for structured document editing.
9
10
```typescript { .api }
11
/**
12
* XML container that can hold XML elements and text nodes
13
*/
14
class YXmlFragment {
15
constructor();
16
17
/** Number of child elements in the fragment */
18
readonly length: number;
19
20
/** First child element or null if empty */
21
readonly firstChild: YXmlElement | YXmlText | null;
22
}
23
```
24
25
**Fragment Modification Methods:**
26
27
```typescript { .api }
28
/**
29
* Insert child nodes at the specified index
30
* @param index - Position to insert at
31
* @param content - Array of XML elements or text nodes to insert
32
*/
33
insert(index: number, content: Array<YXmlElement | YXmlText>): void;
34
35
/**
36
* Insert child nodes after a reference node
37
* @param ref - Reference node to insert after (null for beginning)
38
* @param content - Array of XML elements or text nodes to insert
39
*/
40
insertAfter(ref: null | Item | YXmlElement | YXmlText, content: Array<YXmlElement | YXmlText>): void;
41
42
/**
43
* Delete child nodes starting at index
44
* @param index - Starting position for deletion
45
* @param length - Number of children to delete (default: 1)
46
*/
47
delete(index: number, length?: number): void;
48
49
/**
50
* Append child nodes to the end
51
* @param content - Array of XML elements or text nodes to append
52
*/
53
push(content: Array<YXmlElement | YXmlText>): void;
54
55
/**
56
* Prepend child nodes to the beginning
57
* @param content - Array of XML elements or text nodes to prepend
58
*/
59
unshift(content: Array<YXmlElement | YXmlText>): void;
60
```
61
62
**Fragment Access Methods:**
63
64
```typescript { .api }
65
/**
66
* Get child node at the specified index
67
* @param index - Index of child to retrieve
68
* @returns Child node or undefined
69
*/
70
get(index: number): YXmlElement | YXmlText;
71
72
/**
73
* Get slice of children as JavaScript Array
74
* @param start - Start index (default: 0)
75
* @param end - End index (default: length)
76
* @returns Array of child nodes
77
*/
78
slice(start?: number, end?: number): Array<YXmlElement | YXmlText>;
79
80
/**
81
* Convert all children to JavaScript Array
82
* @returns Array of all child nodes
83
*/
84
toArray(): Array<YXmlElement | YXmlText | YXmlHook>;
85
```
86
87
**Fragment Iteration and Selection:**
88
89
```typescript { .api }
90
/**
91
* Execute function for each child node
92
* @param f - Function to execute for each child
93
*/
94
forEach(f: (item: YXmlElement | YXmlText, index: number, fragment: YXmlFragment) => void): void;
95
96
/**
97
* Create a tree walker for traversing the fragment
98
* @param filter - Optional filter function for nodes
99
* @returns Tree walker instance
100
*/
101
createTreeWalker(filter?: (node: AbstractType<any>) => boolean): YXmlTreeWalker;
102
103
/**
104
* Find the first element matching a CSS selector
105
* @param query - CSS selector string
106
* @returns First matching element or null
107
*/
108
querySelector(query: string): YXmlElement | YXmlText | YXmlHook | null;
109
110
/**
111
* Find all elements matching a CSS selector
112
* @param query - CSS selector string
113
* @returns Array of matching elements
114
*/
115
querySelectorAll(query: string): Array<YXmlElement | YXmlText | YXmlHook | null>;
116
```
117
118
**Fragment Serialization:**
119
120
```typescript { .api }
121
/**
122
* Convert fragment to XML string
123
* @returns XML string representation
124
*/
125
toString(): string;
126
127
/**
128
* Convert to JSON representation
129
* @returns JSON string
130
*/
131
toJSON(): string;
132
133
/**
134
* Convert to DOM DocumentFragment
135
* @param document - Document to create nodes in (default: globalThis.document)
136
* @param hooks - Custom hooks for special elements
137
* @param binding - Optional binding object
138
* @returns DOM DocumentFragment
139
*/
140
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): DocumentFragment;
141
142
/**
143
* Create a copy of the fragment
144
* @returns New YXmlFragment with same content
145
*/
146
clone(): YXmlFragment;
147
```
148
149
**Usage Examples:**
150
151
```typescript
152
import * as Y from "yjs";
153
154
const doc = new Y.Doc();
155
const xmlFragment = doc.getXmlFragment("document");
156
157
// Create XML elements
158
const header = new Y.XmlElement("h1");
159
const paragraph = new Y.XmlElement("p");
160
const textNode = new Y.XmlText();
161
162
textNode.insert(0, "Hello World!");
163
header.insert(0, [textNode]);
164
165
// Insert into fragment
166
xmlFragment.push([header, paragraph]);
167
168
// Query elements
169
const h1 = xmlFragment.querySelector("h1");
170
const allPs = xmlFragment.querySelectorAll("p");
171
172
// Convert to DOM
173
const domFragment = xmlFragment.toDOM();
174
document.body.appendChild(domFragment);
175
```
176
177
### YXmlElement
178
179
XML element with attributes that can contain child elements and text nodes.
180
181
```typescript { .api }
182
/**
183
* XML element with attributes and children
184
*/
185
class YXmlElement<KV = { [key: string]: any }> extends YXmlFragment {
186
constructor(nodeName?: string);
187
188
/** Tag name of the XML element */
189
readonly nodeName: string;
190
191
/** Next sibling element or null */
192
readonly nextSibling: YXmlElement | YXmlText | null;
193
194
/** Previous sibling element or null */
195
readonly prevSibling: YXmlElement | YXmlText | null;
196
}
197
```
198
199
**Element Attribute Methods:**
200
201
```typescript { .api }
202
/**
203
* Set an attribute on the element
204
* @param attributeName - Name of the attribute
205
* @param attributeValue - Value to set
206
*/
207
setAttribute<KEY extends keyof KV>(attributeName: KEY, attributeValue: KV[KEY]): void;
208
209
/**
210
* Get an attribute from the element
211
* @param attributeName - Name of the attribute
212
* @returns Attribute value or undefined
213
*/
214
getAttribute<KEY extends keyof KV>(attributeName: KEY): KV[KEY] | undefined;
215
216
/**
217
* Check if element has an attribute
218
* @param attributeName - Name of the attribute to check
219
* @returns True if attribute exists
220
*/
221
hasAttribute(attributeName: string): boolean;
222
223
/**
224
* Remove an attribute from the element
225
* @param attributeName - Name of the attribute to remove
226
*/
227
removeAttribute(attributeName: string): void;
228
229
/**
230
* Get all attributes from the element
231
* @param snapshot - Optional snapshot for historical state
232
* @returns Object with all attributes
233
*/
234
getAttributes(snapshot?: Snapshot): { [key: string]: any };
235
```
236
237
**Element Serialization:**
238
239
```typescript { .api }
240
/**
241
* Convert element to XML string with attributes
242
* @returns XML string representation
243
*/
244
toString(): string;
245
246
/**
247
* Convert to DOM Element
248
* @param document - Document to create element in (default: globalThis.document)
249
* @param hooks - Custom hooks for special elements
250
* @param binding - Optional binding object
251
* @returns DOM Element
252
*/
253
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Element;
254
255
/**
256
* Create a copy of the element
257
* @returns New YXmlElement with same content and attributes
258
*/
259
clone(): YXmlElement<KV>;
260
```
261
262
**Usage Examples:**
263
264
```typescript
265
import * as Y from "yjs";
266
267
const doc = new Y.Doc();
268
const xmlFragment = doc.getXmlFragment("document");
269
270
// Create an element with attributes
271
const div = new Y.XmlElement("div");
272
div.setAttribute("class", "container");
273
div.setAttribute("id", "main-content");
274
275
// Add text content
276
const text = new Y.XmlText();
277
text.insert(0, "Hello World!");
278
div.insert(0, [text]);
279
280
// Create nested structure
281
const article = new Y.XmlElement("article");
282
const title = new Y.XmlElement("h2");
283
const titleText = new Y.XmlText();
284
titleText.insert(0, "Article Title");
285
title.insert(0, [titleText]);
286
287
article.push([title, div]);
288
xmlFragment.push([article]);
289
290
// Work with attributes
291
console.log(div.getAttribute("class")); // "container"
292
div.removeAttribute("id");
293
294
// Convert to DOM
295
const domElement = article.toDOM();
296
```
297
298
### YXmlText
299
300
XML text node with formatting support for rich text within XML structures.
301
302
```typescript { .api }
303
/**
304
* XML text node with rich formatting capabilities
305
*/
306
class YXmlText extends YText {
307
constructor();
308
309
/** Next sibling element or null */
310
readonly nextSibling: YXmlElement | YXmlText | null;
311
312
/** Previous sibling element or null */
313
readonly prevSibling: YXmlElement | YXmlText | null;
314
}
315
```
316
317
**XML Text Methods:**
318
319
```typescript { .api }
320
/**
321
* Convert to formatted XML string
322
* @returns XML string with formatting
323
*/
324
toString(): string;
325
326
/**
327
* Convert to JSON representation
328
* @returns JSON string
329
*/
330
toJSON(): string;
331
332
/**
333
* Convert to DOM Text node
334
* @param document - Document to create text node in (default: globalThis.document)
335
* @param hooks - Custom hooks for special formatting
336
* @param binding - Optional binding object
337
* @returns DOM Text node
338
*/
339
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Text;
340
341
/**
342
* Create a copy of the text node
343
* @returns New YXmlText with same content
344
*/
345
clone(): YXmlText;
346
```
347
348
**Usage Examples:**
349
350
```typescript
351
import * as Y from "yjs";
352
353
const doc = new Y.Doc();
354
const xmlFragment = doc.getXmlFragment("document");
355
356
// Create formatted text
357
const xmlText = new Y.XmlText();
358
xmlText.insert(0, "Hello ");
359
xmlText.insert(6, "World", { bold: true });
360
xmlText.insert(11, "!");
361
362
// Add to element
363
const paragraph = new Y.XmlElement("p");
364
paragraph.insert(0, [xmlText]);
365
xmlFragment.push([paragraph]);
366
367
// Convert to DOM
368
const domText = xmlText.toDOM();
369
```
370
371
### YXmlHook
372
373
Custom XML element hook for extending XML functionality with custom components.
374
375
```typescript { .api }
376
/**
377
* Custom XML hook for extending functionality
378
*/
379
class YXmlHook extends YMap {
380
constructor(hookName: string);
381
382
/** Name of the hook */
383
readonly hookName: string;
384
}
385
```
386
387
**Hook Methods:**
388
389
```typescript { .api }
390
/**
391
* Convert hook to DOM element using custom rendering
392
* @param document - Document to create element in (default: globalThis.document)
393
* @param hooks - Hook implementation functions
394
* @param binding - Optional binding object
395
* @returns DOM Element
396
*/
397
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Element;
398
399
/**
400
* Create a copy of the hook
401
* @returns New YXmlHook with same hook name and data
402
*/
403
clone(): YXmlHook;
404
```
405
406
**Usage Examples:**
407
408
```typescript
409
import * as Y from "yjs";
410
411
const doc = new Y.Doc();
412
const xmlFragment = doc.getXmlFragment("document");
413
414
// Create a custom hook
415
const customComponent = new Y.XmlHook("custom-widget");
416
customComponent.set("type", "chart");
417
customComponent.set("data", [1, 2, 3, 4, 5]);
418
419
xmlFragment.push([customComponent]);
420
421
// Convert to DOM with custom hook handler
422
const domFragment = xmlFragment.toDOM(document, {
423
"custom-widget": (hook) => {
424
const element = document.createElement("div");
425
element.className = "custom-widget";
426
element.textContent = `Chart with ${hook.get("data").length} points`;
427
return element;
428
}
429
});
430
```
431
432
### YXmlTreeWalker
433
434
Iterator for traversing XML tree structures with optional filtering.
435
436
```typescript { .api }
437
/**
438
* Tree walker for traversing XML structures
439
*/
440
class YXmlTreeWalker {
441
constructor(root: YXmlFragment | YXmlElement, filter?: (node: AbstractType<any>) => boolean);
442
443
/**
444
* Get next node in traversal
445
* @returns Iterator result with next node
446
*/
447
next(): IteratorResult<YXmlElement | YXmlText | YXmlHook>;
448
449
/**
450
* Iterator support for for...of loops
451
*/
452
[Symbol.iterator](): YXmlTreeWalker;
453
}
454
```
455
456
**Usage Examples:**
457
458
```typescript
459
import * as Y from "yjs";
460
461
const doc = new Y.Doc();
462
const xmlFragment = doc.getXmlFragment("document");
463
464
// Create tree structure
465
const root = new Y.XmlElement("div");
466
const child1 = new Y.XmlElement("p");
467
const child2 = new Y.XmlElement("span");
468
root.push([child1, child2]);
469
xmlFragment.push([root]);
470
471
// Walk the tree
472
const walker = xmlFragment.createTreeWalker();
473
for (const node of walker) {
474
if (node instanceof Y.XmlElement) {
475
console.log(`Element: ${node.nodeName}`);
476
} else if (node instanceof Y.XmlText) {
477
console.log(`Text: ${node.toString()}`);
478
}
479
}
480
481
// Walk with filter
482
const elementWalker = xmlFragment.createTreeWalker(
483
node => node instanceof Y.XmlElement
484
);
485
for (const element of elementWalker) {
486
console.log(`Element: ${element.nodeName}`);
487
}
488
```