001/* 002 * ============================================================================ 003 * Copyright © 2002-2023 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * 007 * Licensed to the public under the agreements of the GNU Lesser General Public 008 * License, version 3.0 (the "License"). You may obtain a copy of the License at 009 * 010 * http://www.gnu.org/licenses/lgpl.html 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 015 * License for the specific language governing permissions and limitations 016 * under the License. 017 */ 018 019package org.tquadrat.foundation.xml.builder; 020 021import static org.apiguardian.api.API.Status.STABLE; 022import static org.tquadrat.foundation.lang.Objects.requireNotEmptyArgument; 023import static org.tquadrat.foundation.xml.builder.XMLBuilderUtils.getNMTokenValidator; 024 025import java.net.URI; 026import java.net.URISyntaxException; 027import java.time.Instant; 028import java.time.LocalDate; 029import java.time.LocalDateTime; 030import java.time.ZonedDateTime; 031import java.util.Optional; 032 033import org.apiguardian.api.API; 034import org.tquadrat.foundation.annotation.ClassVersion; 035import org.tquadrat.foundation.xml.builder.internal.XMLDocumentImpl; 036import org.tquadrat.foundation.xml.builder.spi.Document; 037 038/** 039 * The definition for an XML document. 040 * 041 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 042 * @version $Id: XMLDocument.java 1071 2023-09-30 01:49:32Z tquadrat $ 043 * @since 0.0.5 044 * 045 * @UMLGraph.link 046 */ 047@SuppressWarnings( {"ClassWithTooManyMethods"} ) 048@ClassVersion( sourceVersion = "$Id: XMLDocument.java 1071 2023-09-30 01:49:32Z tquadrat $" ) 049@API( status = STABLE, since = "0.0.5" ) 050public sealed interface XMLDocument extends Document<XMLElement> 051 permits XMLDocumentImpl 052{ 053 /*---------*\ 054 ====** Methods **========================================================== 055 \*---------*/ 056 /** 057 * Adds a child to the root element of this document. 058 * 059 * @param child The child to add. 060 * @return This instance. 061 * @throws IllegalArgumentException The child is not allowed for the 062 * root element of this document, or the root element does not allow 063 * adding children at all. 064 * @throws IllegalStateException The child has already a parent that is 065 * not the root XML element. 066 */ 067 @SuppressWarnings( "UnusedReturnValue" ) 068 public default XMLDocument addChild( final XMLElement child ) throws IllegalArgumentException, IllegalStateException 069 { 070 getRootElement().addChild( child ); 071 072 //---* Done *---------------------------------------------------------- 073 return this; 074 } // addChild() 075 076 /** 077 * Adds a comment to the root element of this document. 078 * 079 * @param comment The comment to add. 080 * @return This instance. 081 * @throws IllegalArgumentException The root element does not allow 082 * adding comments. 083 */ 084 @SuppressWarnings( "UnusedReturnValue" ) 085 public default XMLDocument addComment( final CharSequence comment ) throws IllegalArgumentException 086 { 087 getRootElement().addComment( comment ); 088 089 //---* Done *---------------------------------------------------------- 090 return this; 091 } // // addComment() 092 093 /** 094 * Adds a comment to the document itself. 095 * 096 * @param comment The comment to add. 097 * @return This instance. 098 * @throws IllegalArgumentException The document does not allow adding 099 * comments. 100 */ 101 @SuppressWarnings( "UnusedReturnValue" ) 102 public default XMLDocument addDocumentComment( final CharSequence comment ) throws IllegalArgumentException 103 { 104 throw new IllegalArgumentException( "No comment allowed for this document" ); 105 } // addDocumentComment() 106 107 /** 108 * Adds predefined XML markup to the root element of this document. The 109 * given markup will not be validated, it just may not be {@code null}. So 110 * the caller is responsible that it will be proper XML.<br> 111 * <br>As the markup may be formatted differently (or not formatted at 112 * all), the pretty printed output may be distorted when this is used. 113 * 114 * @param markup The XML markup. 115 * @return This instance. 116 * @throws IllegalArgumentException The root element does not allow 117 * adding children at all. 118 */ 119 @SuppressWarnings( "UnusedReturnValue" ) 120 public default XMLDocument addPredefinedMarkup( final CharSequence markup ) throws IllegalArgumentException 121 { 122 getRootElement().addPredefinedMarkup( markup ); 123 124 //---* Done *---------------------------------------------------------- 125 return this; 126 } // addPredefinedMarkup() 127 128 /** 129 * Adds a processing instruction to this document. 130 * 131 * @param processingInstruction The procession instruction to add. 132 * @return This instance. 133 * @throws IllegalArgumentException This document does not allow adding 134 * processing instructions. 135 * @throws IllegalStateException The processing instruction has already 136 * a parent. 137 */ 138 @SuppressWarnings( "UnusedReturnValue" ) 139 public default XMLDocument addProcessingInstruction( final ProcessingInstruction processingInstruction ) throws IllegalArgumentException, IllegalStateException 140 { 141 throw new IllegalArgumentException( "No processing instructions allowed for this document" ); 142 } // addProcessingInstruction() 143 144 /** 145 * Sets the attribute with the given name to the root element of this 146 * document.<br> 147 * <br>The method uses 148 * {@link Boolean#toString(boolean)} 149 * to convert the provided flag to a {@code String}. 150 * 151 * @param name The name of the attribute; the name is case-sensitive. 152 * @param flag The attribute's value. 153 * @return This instance. 154 * @throws IllegalArgumentException The attribute is not allowed for 155 * the root element, or the root element does not allow attributes at 156 * all. 157 */ 158 public default XMLDocument setAttribute( final String name, final boolean flag ) throws IllegalArgumentException 159 { 160 getRootElement().setAttribute( name, flag ); 161 162 //---* Done *---------------------------------------------------------- 163 return this; 164 } // setAttribute() 165 166 /** 167 * Sets the attribute with the given name to the root element of this 168 * document.<br> 169 * <br>The method uses 170 * {@link Boolean#toString()} 171 * to convert the provided flag to a {@code String}. 172 * 173 * @param name The name of the attribute; the name is case-sensitive. 174 * @param flag The attribute's value; if {@code null} the 175 * attribute will be removed. 176 * @return This instance. 177 * @throws IllegalArgumentException The attribute is not allowed for 178 * the root element, or the root element does not allow attributes at 179 * all. 180 */ 181 public default XMLDocument setAttribute( final String name, final Boolean flag ) throws IllegalArgumentException 182 { 183 getRootElement().setAttribute( name, flag ); 184 185 //---* Done *---------------------------------------------------------- 186 return this; 187 } // setAttribute() 188 189 /** 190 * Sets the attribute with the given name to the root element of this 191 * document. 192 * 193 * @param name The name of the attribute; the name is case-sensitive. 194 * @param value The attribute's value; if {@code null} the 195 * attribute will be removed. 196 * @return This instance. 197 * @throws IllegalArgumentException The attribute is not allowed for 198 * the root element, or the root element does not allow attributes at 199 * all. 200 */ 201 public default XMLDocument setAttribute( final String name, final CharSequence value ) throws IllegalArgumentException 202 { 203 getRootElement().setAttribute( name, value ); 204 205 //---* Done *---------------------------------------------------------- 206 return this; 207 } // setAttribute() 208 209 /** 210 * Sets the attribute with the given name to the root element of this 211 * document. 212 * 213 * @param name The name of the attribute; the name is case-sensitive. 214 * @param value The attribute's value; if {@code null} the 215 * attribute will be removed. 216 * @param append If not 217 * {@linkplain Optional#empty() empty}, the new value will be appended 218 * on an already existing one, and this sequence is used as the 219 * separator. 220 * @return This instance. 221 * @throws IllegalArgumentException The attribute is not allowed for 222 * the root element, or the root element does not allow attributes at 223 * all. 224 */ 225 @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) 226 public default XMLDocument setAttribute( final String name, final CharSequence value, final Optional<? extends CharSequence> append ) throws IllegalArgumentException 227 { 228 getRootElement().setAttribute( name, value, append ); 229 230 //---* Done *---------------------------------------------------------- 231 return this; 232 } // setAttribute() 233 234 /** 235 * Sets the attribute with the given name to the root element of this 236 * document.<br> 237 * <br>The method uses 238 * {@link Double#toString(double)} 239 * to convert the provided number to a {@code String}. 240 * 241 * @param name The name of the attribute; the name is case-sensitive. 242 * @param number The attribute's value. 243 * @return This instance. 244 * @throws IllegalArgumentException The attribute is not allowed for 245 * the root element, or the root element does not allow attributes at 246 * all. 247 */ 248 public default XMLDocument setAttribute( final String name, final double number ) throws IllegalArgumentException 249 { 250 getRootElement().setAttribute( name, number ); 251 252 //---* Done *---------------------------------------------------------- 253 return this; 254 } // setAttribute() 255 256 /** 257 * Sets the attribute with the given name to the root element of this 258 * document.<br> 259 * <br>The method uses 260 * {@link Enum#name()} 261 * to convert the provided value to a {@code String}. 262 * 263 * @param <E> The concrete enum type of {@code value}. 264 * @param name The name of the attribute; the name is case-sensitive. 265 * @param enumValue The attribute's value; if {@code null} the 266 * attribute will be removed. 267 * @return This instance. 268 * @throws IllegalArgumentException The attribute is not allowed for 269 * the root element, or the root element does not allow attributes at 270 * all. 271 */ 272 public default <E extends Enum<E>> XMLDocument setAttribute( final String name, final E enumValue ) throws IllegalArgumentException 273 { 274 getRootElement().setAttribute( name, enumValue ); 275 276 //---* Done *---------------------------------------------------------- 277 return this; 278 } // setAttribute() 279 280 /** 281 * Sets the attribute with the given name to the root element of this 282 * document.<br> 283 * <br>The method uses 284 * {@link Instant#toString()} 285 * to convert the provided number to a {@code String}. 286 * 287 * @param name The name of the attribute; the name is case-sensitive. 288 * @param date The attribute's value; if {@code null} the 289 * attribute will be removed. 290 * @return This instance. 291 * @throws IllegalArgumentException The attribute is not allowed for 292 * the root element, or the root element does not allow attributes at 293 * all. 294 */ 295 public default XMLDocument setAttribute( final String name, final Instant date ) throws IllegalArgumentException 296 { 297 getRootElement().setAttribute( name, date ); 298 299 //---* Done *---------------------------------------------------------- 300 return this; 301 } // setAttribute() 302 303 /** 304 * Sets the attribute with the given name to the root element of this 305 * document.<br> 306 * <br>The method uses 307 * {@link Integer#toString(int)} 308 * to convert the provided number to a {@code String}. 309 * 310 * @param name The name of the attribute; the name is case-sensitive. 311 * @param number The attribute's value. 312 * @return This instance. 313 * @throws IllegalArgumentException The attribute is not allowed for 314 * the root element, or the root element does not allow attributes at 315 * all. 316 */ 317 public default XMLDocument setAttribute( final String name, final int number ) throws IllegalArgumentException 318 { 319 getRootElement().setAttribute( name, number ); 320 321 //---* Done *---------------------------------------------------------- 322 return this; 323 } // setAttribute() 324 325 /** 326 * Sets the attribute with the given name to the root element of this 327 * document.<br> 328 * <br>The method uses 329 * {@link LocalDate#toString()} 330 * to convert the provided number to a {@code String}. 331 * 332 * @param name The name of the attribute; the name is case-sensitive. 333 * @param date The attribute's value; if {@code null} the 334 * attribute will be removed. 335 * @return This instance. 336 * @throws IllegalArgumentException The attribute is not allowed for 337 * the root element, or the root element does not allow attributes at 338 * all. 339 */ 340 public default XMLDocument setAttribute( final String name, final LocalDate date ) throws IllegalArgumentException 341 { 342 getRootElement().setAttribute( name, date ); 343 344 //---* Done *---------------------------------------------------------- 345 return this; 346 } // setAttribute() 347 348 /** 349 * Sets the attribute with the given name to the root element of this 350 * document.<br> 351 * <br>The method uses 352 * {@link LocalDateTime#toString()} 353 * to convert the provided number to a {@code String}. 354 * 355 * @param name The name of the attribute; the name is case-sensitive. 356 * @param date The attribute's value; if {@code null} the 357 * attribute will be removed. 358 * @return This instance. 359 * @throws IllegalArgumentException The attribute is not allowed for 360 * the root element, or the root element does not allow attributes at 361 * all. 362 */ 363 public default XMLDocument setAttribute( final String name, final LocalDateTime date ) throws IllegalArgumentException 364 { 365 getRootElement().setAttribute( name, date ); 366 367 //---* Done *---------------------------------------------------------- 368 return this; 369 } // setAttribute() 370 371 /** 372 * Sets the attribute with the given name to the root element of this 373 * document.<br> 374 * <br>The method uses 375 * {@link Long#toString(long)} 376 * to convert the provided number to a {@code String}. 377 * 378 * @param name The name of the attribute; the name is case-sensitive. 379 * @param number The attribute's value. 380 * @return This instance. 381 * @throws IllegalArgumentException The attribute is not allowed for 382 * the root element, or the root element does not allow attributes at 383 * all. 384 */ 385 public default XMLDocument setAttribute( final String name, final long number ) throws IllegalArgumentException 386 { 387 getRootElement().setAttribute( name, number ); 388 389 //---* Done *---------------------------------------------------------- 390 return this; 391 } // setAttribute() 392 393 /** 394 * Sets the attribute with the given name to the root element of this 395 * document.<br> 396 * <br>The method uses 397 * {@link Number#toString()} 398 * to convert the provided number to a {@code String}. 399 * 400 * @param name The name of the attribute; the name is case-sensitive. 401 * @param number The attribute's value; if {@code null} the 402 * attribute will be removed. 403 * @return This instance. 404 * @throws IllegalArgumentException The attribute is not allowed for 405 * the root element, or the root element does not allow attributes at 406 * all. 407 */ 408 public default XMLDocument setAttribute( final String name, final Number number ) throws IllegalArgumentException 409 { 410 getRootElement().setAttribute( name, number ); 411 412 //---* Done *---------------------------------------------------------- 413 return this; 414 } // setAttribute() 415 416 /** 417 * Sets the attribute with the given name to the root element of this 418 * document.<br> 419 * <br>The method uses 420 * {@link ZonedDateTime#toString()} 421 * to convert the provided number to a {@code String}. 422 * 423 * @param name The name of the attribute; the name is case-sensitive. 424 * @param date The attribute's value; if {@code null} the 425 * attribute will be removed. 426 * @return This instance. 427 * @throws IllegalArgumentException The attribute is not allowed for 428 * the root element, or the root element does not allow attributes at 429 * all. 430 */ 431 public default XMLDocument setAttribute( final String name, final ZonedDateTime date ) throws IllegalArgumentException 432 { 433 getRootElement().setAttribute( name, date ); 434 435 //---* Done *---------------------------------------------------------- 436 return this; 437 } // setAttribute() 438 439 /** 440 * Sets the attribute with the given name to the root element of this 441 * document if the provided value is not empty.<br> 442 * <br>The method uses 443 * {@link org.tquadrat.foundation.util.StringUtils#isNotEmpty(CharSequence)} 444 * to test if the given value is empty. 445 * 446 * @param name The name of the attribute. 447 * @param value The value for the attribute; can be {@code null}. 448 * @return This instance. 449 * @throws IllegalArgumentException The attribute is not allowed for 450 * the root element, or the root element does not allow attributes at 451 * all. 452 */ 453 @SuppressWarnings( "UnusedReturnValue" ) 454 public default XMLDocument setAttributeIfNotEmpty( final String name, final CharSequence value ) throws IllegalArgumentException 455 { 456 getRootElement().setAttributeIfNotEmpty( name, value ); 457 458 //---* Done *---------------------------------------------------------- 459 return this; 460 } // setAttributeIfNotEmpty() 461 462 /** 463 * Sets the attribute with the given name to the root element of this 464 * document if the provided value is not empty. 465 * 466 * @param name The name of the attribute. 467 * @param optional The value for the attribute. 468 * @return This instance. 469 * @throws IllegalArgumentException The attribute is not allowed for 470 * the root element, or the root element does not allow attributes at 471 * all. 472 */ 473 @SuppressWarnings( {"UnusedReturnValue", "OptionalUsedAsFieldOrParameterType"} ) 474 public default XMLDocument setAttributeIfNotEmpty( final String name, final Optional<? extends CharSequence> optional ) throws IllegalArgumentException 475 { 476 getRootElement().setAttributeIfNotEmpty( name, optional ); 477 478 //---* Done *---------------------------------------------------------- 479 return this; 480 } // setAttributeIfNotEmpty() 481 482 /** 483 * Sets the id for the root element of this document.<br> 484 * <br>The value will be validated using the method that is provided by a 485 * call to 486 * {@link XMLBuilderUtils#getNMTokenValidator()}. 487 * 488 * @param id The id. 489 * @return This instance. 490 * @throws IllegalArgumentException The attribute is not allowed for 491 * the root element, or the root element does not allow attributes at 492 * all. 493 * 494 * @see org.tquadrat.foundation.lang.CommonConstants#XMLATTRIBUTE_Id 495 */ 496 public default XMLDocument setId( final String id ) throws IllegalArgumentException 497 { 498 if( !getNMTokenValidator().test( requireNotEmptyArgument( id, "id" ) ) ) throw new IllegalArgumentException( "Invalid id: %s".formatted( id ) ); 499 getRootElement().setId( id ); 500 501 //---* Done *---------------------------------------------------------- 502 return this; 503 } // setId() 504 505 /** 506 * Sets the given namespace to the root element of this document. 507 * 508 * @param identifier The namespace identifier. 509 * @return This instance. 510 * @throws IllegalArgumentException Namespaces are not allowed for this 511 * element. 512 * @throws URISyntaxException The provided URI String is invalid. 513 */ 514 public default XMLDocument setNamespace( final String identifier ) throws IllegalArgumentException, URISyntaxException 515 { 516 getRootElement().setNamespace( new Namespace( identifier ) ); 517 518 //---* Done *---------------------------------------------------------- 519 return this; 520 } // setNamespace() 521 522 /** 523 * Sets the given namespace to the root element of this document. 524 * 525 * @param identifier The namespace identifier. 526 * @return This instance. 527 * @throws IllegalArgumentException Namespaces are not allowed for this 528 * element. 529 */ 530 public default XMLDocument setNamespace( final URI identifier ) throws IllegalArgumentException 531 { 532 getRootElement().setNamespace( new Namespace( identifier ) ); 533 534 //---* Done *---------------------------------------------------------- 535 return this; 536 } // setNamespace() 537 538 /** 539 * Sets the given namespace to the root element of this document.<br> 540 * <br>The given prefix is validated using the method that is 541 * provided by 542 * {@link XMLBuilderUtils#getPrefixValidator()}. 543 * 544 * @param prefix The namespace prefix. 545 * @param identifier The namespace identifier. 546 * @return This instance. 547 * @throws IllegalArgumentException Namespaces are not allowed for this 548 * element. 549 * @throws URISyntaxException The provided URI String is invalid. 550 */ 551 public default XMLDocument setNamespace( final String prefix, final String identifier ) throws IllegalArgumentException, URISyntaxException 552 { 553 getRootElement().setNamespace( new Namespace( prefix, identifier ) ); 554 555 //---* Done *---------------------------------------------------------- 556 return this; 557 } // setNamespace() 558 559 /** 560 * Sets the given namespace to the root element of this document.<br> 561 * <br>The given prefix is validated using the method that is 562 * provided by 563 * {@link XMLBuilderUtils#getPrefixValidator()}. 564 * 565 * @param prefix The namespace prefix. 566 * @param identifier The namespace identifier. 567 * @return This instance. 568 * @throws IllegalArgumentException Namespaces are not allowed for this 569 * element. 570 */ 571 public default XMLDocument setNamespace( final String prefix, final URI identifier ) throws IllegalArgumentException 572 { 573 getRootElement().setNamespace( new Namespace( prefix, identifier ) ); 574 575 //---* Done *---------------------------------------------------------- 576 return this; 577 } // setNamespace() 578 579 /** 580 * Sets the given namespace to the root element of this document. 581 * 582 * @param namespace The namespace. 583 * @return This instance. 584 * @throws IllegalArgumentException Namespaces are not allowed for this 585 * element. 586 */ 587 @SuppressWarnings( "UseOfConcreteClass" ) 588 public default XMLDocument setNamespace( final Namespace namespace ) throws IllegalArgumentException 589 { 590 getRootElement().setNamespace( namespace ); 591 592 //---* Done *---------------------------------------------------------- 593 return this; 594 } // setNamespace() 595} 596// interface XMLDocument 597 598/* 599 * End of File 600 */