'
13 |
14 | hr_faded: '
'
15 | hr_shaded: '
'
--------------------------------------------------------------------------------
/docs/_data/definitions.yml:
--------------------------------------------------------------------------------
1 | elephant: "This is a sample definition."
2 |
3 | baseball: "Baseball is considered America's pasttime sport, though that may be more of a historical term than a current one. There's a lot more excitement about football than baseball. A baseball game is somewhat of a snooze to watch, for the most part."
4 |
5 | basketball: "Basketball is a sport involving two teams of five players each competing to put a ball through a small circular rim 10 feet above the ground. Basketball requires players to be in top physical condition, since they spend most of the game running back and forth along a 94-foot-long floor."
6 |
7 | football: "No doubt the most fun sport to watch, football also manages to accrue the most injuries with the players. From concussions to blown knees, football players have short sport lives."
8 |
9 | soccer: "If there's one sport that dominates the world landscape, it's soccer. However, US soccer fans are few and far between. Apart from the popularity of soccer during the World Cup, most people don't even know the name of the professional soccer organization in their area."
--------------------------------------------------------------------------------
/docs/_data/glossary.yml:
--------------------------------------------------------------------------------
1 | jekyll_platform: "Jekyll is a static site generator that builds sites using most modern web technologies."
2 |
3 | fractious: "Like a little mischevious child, full of annoying and constant trouble."
4 |
5 | gratuitous: "Something that is unwarranted and uncouth, like the social equivalent of a flagrant foul."
6 |
7 | haughty: "Proud and flaunting it. Holding your head high up like a snooty, too-good-for-everything rich person."
8 |
9 | impertinent: "Someone acting rude and insensitive to others."
10 |
11 | intrepid: "Brave and courageous especially in a difficult, dangerous situation."
--------------------------------------------------------------------------------
/docs/_data/samplelist.yml:
--------------------------------------------------------------------------------
1 | entries:
2 | - title: Sidebar
3 | folders:
4 | - title: Food
5 |
6 | folderitems:
7 | - title: Bananas
8 | url: bananas.html
9 |
10 | subfolders:
11 | - title: Apples
12 |
13 | subfolderitems:
14 | - title: Fuji apples
15 | url: fuji_apples.html
16 |
17 |
18 | - title: Gala apples
19 | url: gala_apples.html
20 |
21 | name:
22 | husband: Tom
23 | wife: Shannon
24 |
25 | bikes:
26 | - title: mountain bikes
27 | - title: road bikes
28 | - title: hybrid bikes
29 |
30 |
31 | salesteams:
32 | - title: Regions
33 | subfolderitems:
34 | - location: US
35 | - location: Spain
36 | - location: France
37 |
38 | toc:
39 | - title: Group 1
40 | subfolderitems:
41 | - page: Thing 1
42 | - page: Thing 2
43 | - page: Thing 3
44 | - title: Group 2
45 | subfolderitems:
46 | - page: Piece 1
47 | - page: Piece 2
48 | - page: Piece 3
49 | - title: Group 3
50 | subfolderitems:
51 | - page: Widget 1
52 | - page: Widget 2
53 | - page: Widget 3
54 |
55 | something: &hello Greetings earthling!
56 | myref: *hello
57 |
58 | about:
59 | - zero
60 | - one
61 | - two
62 | - three
63 |
64 | numbercolors:
65 | - zero:
66 | properties: red
67 | - one:
68 | properties: yellow
69 | - two:
70 | properties: green
71 | - three:
72 | properties: blue
73 |
74 | mypages:
75 | - section1: Section 1
76 | audience: developers
77 | product: acme
78 | url: facebook.com
79 | - section2: Section 2
80 | audience: writers
81 | product: acme
82 | url: google.com
83 | - section3: Section 3
84 | audience: developers
85 | product: acme
86 | url: amazon.com
87 | - section4: Section 4
88 | audience: writers
89 | product: gizmo
90 | url: apple.com
91 | - section5: Section 5
92 | audience: writers
93 | product: acme
94 | url: microsoft.com
95 |
96 | feedback: >
97 | This is my feedback to you.
98 | Even if I include linebreaks here,
99 | all of the linebreaks will be removed when the value is inserted.
100 |
101 | block: |
102 | This pipe does something a little different.
103 | It preserves the breaks.
104 | This is really helpful for code samples,
105 | since you can format the code samples with
106 | the appropriate
107 | white spacing.
108 |
--------------------------------------------------------------------------------
/docs/_data/strings.yml:
--------------------------------------------------------------------------------
1 |
2 |
3 | # placed here for translation purposes
4 | search_placeholder_text: search...
5 | search_no_results_text: No results found.
6 |
--------------------------------------------------------------------------------
/docs/_data/tags.yml:
--------------------------------------------------------------------------------
1 | # Note:
2 | # If you are using the createtag script, don't leave an blank line at the end of this file.
3 | # In other words, the last line must be the last tag in the allowed-tags list.
4 | allowed-tags:
5 | - getting_started
6 | - content_types
7 | - navigation
8 | - formatting
9 | - publishing
10 | - single_sourcing
11 | - special_layouts
12 | - collaboration
13 | - news
14 | - troubleshooting
15 | - mobile
16 |
--------------------------------------------------------------------------------
/docs/_data/terms.yml:
--------------------------------------------------------------------------------
1 | apple: "apple - the fruit of a disiduous tree."
--------------------------------------------------------------------------------
/docs/_data/topnav.yml:
--------------------------------------------------------------------------------
1 | ## Topnav single links
2 | ## if you want to list an external url, use external_url instead of url. the theme will apply a different link base.
3 | topnav:
4 | - title: Topnav
5 | items:
6 | - title: '
GitHub'
7 | external_url: https://github.com/oozcitak/xmlbuilder2
8 | - title: '
npm'
9 | external_url: https://www.npmjs.com/package/xmlbuilder2
10 |
--------------------------------------------------------------------------------
/docs/_includes/archive.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | type: archive
4 | ---
5 |
6 |
9 |
10 |
11 | {{ content }}
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/_includes/callout.html:
--------------------------------------------------------------------------------
1 |
{{include.content}}
2 |
--------------------------------------------------------------------------------
/docs/_includes/commento.html:
--------------------------------------------------------------------------------
1 | {% unless page.comments == false %}
2 |
3 |
4 |
Please enable JavaScript to load the comments.
5 | {% endunless %}
6 |
--------------------------------------------------------------------------------
/docs/_includes/custom/getting_started_series.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Getting Started
4 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/_includes/custom/getting_started_series_next.html:
--------------------------------------------------------------------------------
1 |
{% assign series_pages = site.tags.series_acme %}
2 | {% for p in pages %}
3 | {% if p.series == "Getting Started" %}
4 | {% assign nextTopic = page.weight | plus: "1" %}
5 | {% if p.weight == nextTopic %}
6 | Next: {{p.title}}
7 | {% endif %}
8 | {% endif %}
9 | {% endfor %}
10 |
--------------------------------------------------------------------------------
/docs/_includes/custom/series_acme.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Series Demo
4 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/_includes/custom/series_acme_next.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_includes/custom/usermap.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
→
5 |
6 |
→
7 |
8 |
→
9 |
10 |
→
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/_includes/feedback.html:
--------------------------------------------------------------------------------
1 |
2 | {% if site.feedback_text %}
3 | {% assign feedback_text = site.feedback_text %}
4 | {% else %}
5 | {% assign feedback_text = "Feedback" %}
6 | {% endif %}
7 |
8 | {% if site.feedback_link %}
9 | {{feedback_text}}
10 | {% else %}
11 | {{feedback_text}}
12 | {% endif %}
13 |
14 |
--------------------------------------------------------------------------------
/docs/_includes/footer.html:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/docs/_includes/google_analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% if site.google_analytics %}
4 |
5 |
6 | {% endif %}
--------------------------------------------------------------------------------
/docs/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ page.title }} | {{ site.site_title }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/docs/_includes/head_print.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{% if page.homepage == true %} {{site.homepage_title}} {% elsif page.title %}{{ page.title }}{% endif %} | {{ site.site_title }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/docs/_includes/image.html:
--------------------------------------------------------------------------------
1 |
{% if {{include.url}} %}{% endif %} {% if {{include.url}} %} {% endif %}{% if {{include.caption}} %}{{include.caption}} {% endif %}
2 |
--------------------------------------------------------------------------------
/docs/_includes/important.html:
--------------------------------------------------------------------------------
1 |
Important: {{include.content}}
--------------------------------------------------------------------------------
/docs/_includes/initialize_shuffle.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
100 |
101 |
102 |
103 |
114 |
115 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/docs/_includes/inline_image.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/_includes/links.html:
--------------------------------------------------------------------------------
1 | {% comment %}Get links from each sidebar, as listed in the _config.yml file under sidebars{% endcomment %}
2 |
3 | {% for sidebar in site.sidebars %}
4 | {% for entry in site.data.sidebars[sidebar].entries %}
5 | {% for folder in entry.folders %}
6 | {% for folderitem in folder.folderitems %}
7 | {% if folderitem.url contains "html#" %}
8 | [{{folderitem.url | remove: "/" }}]: {{folderitem.url | remove: "/"}}
9 | {% else %}
10 | [{{folderitem.url | remove: "/" | remove: ".html"}}]: {{folderitem.url | remove: "/"}}
11 | {% endif %}
12 | {% for subfolders in folderitem.subfolders %}
13 | {% for subfolderitem in subfolders.subfolderitems %}
14 | [{{subfolderitem.url | remove: "/" | remove: ".html"}}]: {{subfolderitem.url | remove: "/"}}
15 | {% endfor %}
16 | {% endfor %}
17 | {% endfor %}
18 | {% endfor %}
19 | {% endfor %}
20 | {% endfor %}
21 |
22 |
23 | {% comment %} Get links from topnav {% endcomment %}
24 |
25 | {% for entry in site.data.topnav.topnav %}
26 | {% for item in entry.items %}
27 | {% if item.external_url == null %}
28 | [{{item.url | remove: "/" | remove: ".html"}}]: {{item.url | remove: "/"}}
29 | {% endif %}
30 | {% endfor %}
31 | {% endfor %}
32 |
33 | {% comment %}Get links from topnav dropdowns {% endcomment %}
34 |
35 | {% for entry in site.data.topnav.topnav_dropdowns %}
36 | {% for folder in entry.folders %}
37 | {% for folderitem in folder.folderitems %}
38 | {% if folderitem.external_url == null %}
39 | [{{folderitem.url | remove: "/" | remove: ".html"}}]: {{folderitem.url | remove: "/"}}
40 | {% endif %}
41 | {% endfor %}
42 | {% endfor %}
43 | {% endfor %}
44 |
45 |
--------------------------------------------------------------------------------
/docs/_includes/note.html:
--------------------------------------------------------------------------------
1 |
Note: {{include.content}}
2 |
--------------------------------------------------------------------------------
/docs/_includes/sidebar.html:
--------------------------------------------------------------------------------
1 | {% assign sidebar = site.data.sidebars[page.sidebar].entries %}
2 |
3 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/docs/_includes/taglogic.html:
--------------------------------------------------------------------------------
1 |
The following pages and posts are tagged with {{page.tagName}}
2 |
Title Type Excerpt
3 |
4 | {% assign thisTag = page.tagName %}
5 | {% for page in site.pages %}
6 | {% for tag in page.tags %}
7 | {% if tag == thisTag %}
8 |
9 | {{page.title}}
10 | Page
11 | {% if page.summary %} {{ page.summary | strip_html | strip_newlines | truncate: 160 }} {% else %} {{ page.content | truncatewords: 50 | strip_html }} {% endif %}
12 |
13 | {% endif %}
14 | {% endfor %}
15 | {% endfor %}
16 |
17 | {% assign thisTag = page.tagName %}
18 | {% for post in site.posts %}
19 | {% for tag in post.tags %}
20 | {% if tag == thisTag %}
21 |
22 | {{post.title}}
23 | Post
24 | {% if post.summary %} {{ post.summary | strip_html | strip_newlines | truncate: 160 }} {% else %} {{ post.content | truncatewords: 50 | strip_html }} {% endif %}
25 |
26 | {% endif %}
27 | {% endfor %}
28 | {% endfor %}
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/_includes/tip.html:
--------------------------------------------------------------------------------
1 |
Tip: {{include.content}}
--------------------------------------------------------------------------------
/docs/_includes/toc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/_includes/warning.html:
--------------------------------------------------------------------------------
1 |
Warning: {{include.content}}
--------------------------------------------------------------------------------
/docs/_layouts/default_print.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% include head_print.html %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{content}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/docs/_layouts/none.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {{content}}
--------------------------------------------------------------------------------
/docs/_layouts/page.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
5 |
12 |
13 | {% if page.simple_map == true %}
14 |
15 |
20 |
21 | {% include custom/{{page.map_name}}.html %}
22 |
23 | {% elsif page.complex_map == true %}
24 |
25 |
30 |
31 | {% include custom/{{page.map_name}}.html %}
32 |
33 | {% endif %}
34 |
35 |
36 |
37 | {% if page.summary %}
38 |
{{page.summary}}
39 | {% endif %}
40 |
41 | {% unless page.toc == false %}
42 | {% include toc.html %}
43 | {% endunless %}
44 |
45 |
46 | {% if site.github_editme_path %}
47 |
48 | {% endif %}
49 |
50 | {{content}}
51 |
52 |
63 |
64 | {% include commento.html %}
65 |
66 |
67 |
68 | {% include footer.html %}
69 |
--------------------------------------------------------------------------------
/docs/_layouts/page_print.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default_print
3 | comments: true
4 | ---
5 |
8 |
9 |
10 |
11 | {% if page.summary %}
12 |
{{page.summary}}
13 | {% endif %}
14 | {{ content }}
15 |
16 |
--------------------------------------------------------------------------------
/docs/_layouts/post.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
5 |
6 |
21 |
22 |
23 |
24 | {% if page.summary %}
25 |
{{page.summary}}
26 | {% endif %}
27 |
28 | {{ content }}
29 |
30 |
31 |
32 |
33 |
34 |
35 | {% include commento.html %}
36 |
37 | {{site.data.alerts.hr_shaded}}
38 |
39 | {% include footer.html %}
40 |
--------------------------------------------------------------------------------
/docs/css/boxshadowproperties.css:
--------------------------------------------------------------------------------
1 | /* box-shadow fonts return errors with prince, so extracting here to put in web output only */
2 |
3 | #search-demo-container ul#results-container {
4 | box-shadow: 2px 3px 2px #dedede;
5 | }
6 |
7 |
8 | hr.shaded {
9 | box-shadow: inset 0 6px 6px -6px rgba(0,0,0,0.5);
10 | }
11 |
12 | .videoThumbs img {
13 | box-shadow: 2px 2px 1px #f0f0f0;
14 | }
15 |
16 | .box {
17 | box-shadow: 2px 2px 4px #dedede;
18 | }
19 |
20 | @media (max-width: 1200px) {
21 | .navbar-collapse {
22 | box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/css/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/css/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/css/modern-business.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Start Bootstrap - Modern Business HTML Template (http://startbootstrap.com)
3 | * Code licensed under the Apache License v2.0.
4 | * For details, see http://www.apache.org/licenses/LICENSE-2.0.
5 | */
6 |
7 | /* Global Styles */
8 |
9 | html,
10 | body {
11 | height: 100%;
12 | }
13 |
14 | .img-portfolio {
15 | margin-bottom: 30px;
16 | }
17 |
18 | .img-hover:hover {
19 | opacity: 0.8;
20 | }
21 |
22 | /* Home Page Carousel */
23 |
24 | header.carousel {
25 | height: 50%;
26 | }
27 |
28 | header.carousel .item,
29 | header.carousel .item.active,
30 | header.carousel .carousel-inner {
31 | height: 100%;
32 | }
33 |
34 | header.carousel .fill {
35 | width: 100%;
36 | height: 100%;
37 | background-position: center;
38 | background-size: cover;
39 | }
40 |
41 | /* 404 Page Styles */
42 |
43 | .error-404 {
44 | font-size: 100px;
45 | }
46 |
47 | /* Pricing Page Styles */
48 |
49 | .price {
50 | display: block;
51 | font-size: 50px;
52 | line-height: 50px;
53 | }
54 |
55 | .price sup {
56 | top: -20px;
57 | left: 2px;
58 | font-size: 20px;
59 | }
60 |
61 | .period {
62 | display: block;
63 | font-style: italic;
64 | }
65 |
66 | /* Footer Styles */
67 |
68 | footer {
69 | margin: 50px 0;
70 | }
71 |
72 | /* Responsive Styles */
73 |
74 | @media(max-width:991px) {
75 | .client-img,
76 | .img-related {
77 | margin-bottom: 30px;
78 | }
79 | }
80 |
81 | @media(max-width:767px) {
82 | .img-portfolio {
83 | margin-bottom: 15px;
84 | }
85 |
86 | header.carousel .carousel {
87 | height: 70%;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/docs/css/printstyles.css:
--------------------------------------------------------------------------------
1 |
2 | /*body.print .container {max-width: 650px;}*/
3 |
4 | body {
5 | font-size:14px;
6 | }
7 | .nav ul li a {border-top:0px; background-color:transparent; color: #808080; }
8 | #navig a[href] {color: #595959 !important;}
9 | table .table {max-width:650px;}
10 |
11 | #navig li.sectionHead {font-weight: bold; font-size: 18px; color: #595959 !important; }
12 | #navig li {font-weight: normal; }
13 |
14 | #navig a[href]::after { content: leader(".") target-counter(attr(href), page); }
15 |
16 | a[href]::after {
17 | content: " (page " target-counter(attr(href), page) ")"
18 | }
19 |
20 | a[href^="http:"]::after, a[href^="https:"]::after {
21 | content: "";
22 | }
23 |
24 | a[href] {
25 | color: blue !important;
26 | }
27 | a[href*="mailto"]::after, a[data-toggle="tooltip"]::after, a[href].noCrossRef::after {
28 | content: "";
29 | }
30 |
31 |
32 | @page {
33 | margin: 60pt 90pt 60pt 90pt;
34 | font-family: sans-serif;
35 | font-style:none;
36 | color: gray;
37 |
38 | }
39 |
40 | .printTitle {
41 | line-height:30pt;
42 | font-size:27pt;
43 | font-weight: bold;
44 | letter-spacing: -.5px;
45 | margin-bottom:25px;
46 | }
47 |
48 | .printSubtitle {
49 | font-size: 19pt;
50 | color: #cccccc !important;
51 | font-family: "Grotesque MT Light";
52 | line-height: 22pt;
53 | letter-spacing: -.5px;
54 | margin-bottom:20px;
55 | }
56 | .printTitleArea hr {
57 | color: #999999 !important;
58 | height: 2px;
59 | width: 100%;
60 | }
61 |
62 | .printTitleImage {
63 | max-width:300px;
64 | margin-bottom:200px;
65 | }
66 |
67 |
68 | .printTitleImage {
69 | max-width: 250px;
70 | }
71 |
72 | #navig {
73 | /*page-break-before: always;*/
74 | }
75 |
76 | .copyrightBoilerplate {
77 | page-break-before:always;
78 | font-size:14px;
79 | }
80 |
81 | .lastGeneratedDate {
82 | font-style: italic;
83 | font-size:14px;
84 | color: gray;
85 | }
86 |
87 | .alert a {
88 | text-decoration: none !important;
89 | }
90 |
91 |
92 | body.title { page: title }
93 |
94 | @page title {
95 | @top-left {
96 | content: " ";
97 | }
98 | @top-right {
99 | content: " "
100 | }
101 | @bottom-right {
102 | content: " ";
103 | }
104 | @bottom-left {
105 | content: " ";
106 | }
107 | }
108 |
109 | body.frontmatter { page: frontmatter }
110 | body.frontmatter {counter-reset: page 1}
111 |
112 |
113 | @page frontmatter {
114 | @top-left {
115 | content: prince-script(guideName);
116 | }
117 | @top-right {
118 | content: prince-script(datestamp);
119 | }
120 | @bottom-right {
121 | content: counter(page, lower-roman);
122 | }
123 | @bottom-left {
124 | content: "youremail@domain.com"; }
125 | }
126 |
127 | body.first_page {counter-reset: page 1}
128 |
129 | h1 { string-set: doctitle content() }
130 |
131 | @page {
132 | @top-left {
133 | content: string(doctitle);
134 | font-size: 11px;
135 | font-style: italic;
136 | }
137 | @top-right {
138 | content: prince-script(datestamp);
139 | font-size: 11px;
140 | }
141 |
142 | @bottom-right {
143 | content: "Page " counter(page);
144 | font-size: 11px;
145 | }
146 | @bottom-left {
147 | content: prince-script(guideName);
148 | font-size: 11px;
149 | }
150 | }
151 | .alert {
152 | background-color: #fafafa !important;
153 | border-color: #dedede !important;
154 | color: black;
155 | }
156 |
157 | pre {
158 | background-color: #fafafa;
159 | }
160 |
--------------------------------------------------------------------------------
/docs/css/theme-blue.css:
--------------------------------------------------------------------------------
1 | .summary {
2 | color: #808080;
3 | border-left: 5px solid #ED1951;
4 | font-size:16px;
5 | }
6 |
7 |
8 | h3 {color: #ED1951; }
9 | h4 {color: #808080; }
10 |
11 | .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
12 | background-color: #248ec2;
13 | color: white;
14 | }
15 |
16 | .nav > li.active > a {
17 | background-color: #347DBE;
18 | }
19 |
20 | .nav > li > a:hover {
21 | background-color: #248ec2;
22 | }
23 |
24 | div.navbar-collapse .dropdown-menu > li > a:hover {
25 | background-color: #347DBE;
26 | }
27 |
28 | .nav li.thirdlevel > a {
29 | background-color: #FAFAFA !important;
30 | color: #248EC2;
31 | font-weight: bold;
32 | }
33 |
34 | a[data-toggle="tooltip"] {
35 | color: #649345;
36 | font-style: italic;
37 | cursor: default;
38 | }
39 |
40 | .navbar-inverse {
41 | background-color: #347DBE;
42 | border-color: #015CAE;
43 | }
44 | .navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-brand {
45 | color: white;
46 | }
47 |
48 | .navbar-inverse .navbar-nav>li>a:hover, a.fa.fa-home.fa-lg.navbar-brand:hover {
49 | color: #f0f0f0;
50 | }
51 |
52 | a.navbar-brand:hover {
53 | color: #f0f0f0;
54 | }
55 |
56 | .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
57 | color: #015CAE;
58 | }
59 |
60 | .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
61 | background-color: #015CAE;
62 | color: #ffffff;
63 | }
64 |
65 | .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
66 | border-color: #248ec2 !important;
67 | }
68 |
69 | .btn-primary {
70 | color: #ffffff;
71 | background-color: #347DBE;
72 | border-color: #347DBE;
73 | }
74 |
75 | .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
76 | background-color: #347DBE;
77 | }
78 |
79 | .btn-primary:hover,
80 | .btn-primary:focus,
81 | .btn-primary:active,
82 | .btn-primary.active,
83 | .open .dropdown-toggle.btn-primary {
84 | background-color: #248ec2;
85 | border-color: #347DBE;
86 | }
87 |
88 | .printTitle {
89 | color: #015CAE !important;
90 | }
91 |
92 | body.print h1 {color: #015CAE !important; font-size:28px !important;}
93 | body.print h2 {color: #595959 !important; font-size:20px !important;}
94 | body.print h3 {color: #E50E51 !important; font-size:14px !important;}
95 | body.print h4 {color: #679DCE !important; font-size:14px; font-style: italic !important;}
96 |
97 | .anchorjs-link:hover {
98 | color: #216f9b;
99 | }
100 |
101 | div.sidebarTitle {
102 | color: #015CAE;
103 | }
104 |
105 | li.sidebarTitle {
106 | margin-top:20px;
107 | font-weight:normal;
108 | font-size:130%;
109 | color: #ED1951;
110 | margin-bottom:10px;
111 | margin-left: 5px;
112 |
113 | }
114 |
115 | .navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover {
116 | background-color: #015CAE;
117 | }
118 |
119 | .navbar-inverse .navbar-toggle {
120 | border-color: #015CAE;
121 | }
122 |
--------------------------------------------------------------------------------
/docs/css/theme-green.css:
--------------------------------------------------------------------------------
1 | .summary {
2 | color: #808080;
3 | border-left: 5px solid #E50E51;
4 | font-size:16px;
5 | }
6 |
7 |
8 | h3 {color: #E50E51; }
9 | h4 {color: #808080; }
10 |
11 | .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
12 | background-color: #248ec2;
13 | color: white;
14 | }
15 |
16 | .nav > li.active > a {
17 | background-color: #72ac4a;
18 | }
19 |
20 | .nav > li > a:hover {
21 | background-color: #72ac4a;
22 | }
23 |
24 | div.navbar-collapse .dropdown-menu > li > a:hover {
25 | background-color: #72ac4a;
26 | }
27 |
28 | .navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-brand {
29 | color: white;
30 | }
31 |
32 | .navbar-inverse .navbar-nav>li>a:hover, a.fa.fa-home.fa-lg.navbar-brand:hover {
33 | color: #f0f0f0;
34 | }
35 |
36 | .nav li.thirdlevel > a {
37 | background-color: #FAFAFA !important;
38 | color: #72ac4a;
39 | font-weight: bold;
40 | }
41 |
42 | a[data-toggle="tooltip"] {
43 | color: #649345;
44 | font-style: italic;
45 | cursor: default;
46 | }
47 |
48 | .navbar-inverse {
49 | background-color: #72ac4a;
50 | border-color: #5b893c;
51 | }
52 |
53 | .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
54 | color: #5b893c;
55 | }
56 |
57 | .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
58 | background-color: #5b893c;
59 | color: #ffffff;
60 | }
61 |
62 | /* not sure if using this ...*/
63 | .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
64 | border-color: #72ac4a !important;
65 | }
66 |
67 | .btn-primary {
68 | color: #ffffff;
69 | background-color: #5b893c;
70 | border-color: #5b893c;
71 | }
72 |
73 | .btn-primary:hover,
74 | .btn-primary:focus,
75 | .btn-primary:active,
76 | .btn-primary.active,
77 | .open .dropdown-toggle.btn-primary {
78 | background-color: #72ac4a;
79 | border-color: #5b893c;
80 | }
81 |
82 | .printTitle {
83 | color: #5b893c !important;
84 | }
85 |
86 | body.print h1 {color: #5b893c !important; font-size:28px;}
87 | body.print h2 {color: #595959 !important; font-size:24px;}
88 | body.print h3 {color: #E50E51 !important; font-size:14px;}
89 | body.print h4 {color: #679DCE !important; font-size:14px; font-style: italic;}
90 |
91 | .anchorjs-link:hover {
92 | color: #4f7233;
93 | }
94 |
95 | div.sidebarTitle {
96 | color: #E50E51;
97 | }
98 |
99 | li.sidebarTitle {
100 | margin-top:20px;
101 | font-weight:normal;
102 | font-size:130%;
103 | color: #ED1951;
104 | margin-bottom:10px;
105 | margin-left: 5px;
106 | }
107 |
108 | .navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover {
109 | background-color: #E50E51;
110 | }
111 |
--------------------------------------------------------------------------------
/docs/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | server:
4 | build:
5 | context: .
6 | dockerfile: Dockerfile
7 | image: result/latest
8 | ports:
9 | - "4000:4000"
10 | volumes:
11 | - ".:/src"
--------------------------------------------------------------------------------
/docs/feed.xml:
--------------------------------------------------------------------------------
1 | ---
2 | search: exclude
3 | layout: none
4 | ---
5 |
6 |
7 |
8 |
9 | {{ site.title | xml_escape }}
10 | {{ site.description | xml_escape }}
11 | {{ site.url }}/
12 |
13 | {{ site.time | date_to_rfc822 }}
14 | {{ site.time | date_to_rfc822 }}
15 | Jekyll v{{ jekyll.version }}
16 | {% for post in site.posts limit:10 %}
17 | -
18 |
{{ post.title | xml_escape }}
19 | {{ post.content | xml_escape }}
20 | {{ post.date | date_to_rfc822 }}
21 | {{ post.url | prepend: site.url }}
22 | {{ post.url | prepend: site.url }}
23 | {% for tag in post.tags %}
24 | {{ tag | xml_escape }}
25 | {% endfor %}
26 | {% for tag in page.tags %}
27 | {{ cat | xml_escape }}
28 | {% endfor %}
29 |
30 | {% endfor %}
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/docs/images/android-chrome-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/android-chrome-144x144.png
--------------------------------------------------------------------------------
/docs/images/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/images/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #2b5797
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/favicon.ico
--------------------------------------------------------------------------------
/docs/images/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/mstile-150x150.png
--------------------------------------------------------------------------------
/docs/images/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
14 |
16 |
19 |
22 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/images/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/images/android-chrome-144x144.png",
7 | "sizes": "144x144",
8 | "type": "image/png"
9 | }
10 | ],
11 | "theme_color": "#ffffff",
12 | "background_color": "#ffffff",
13 | "display": "standalone"
14 | }
15 |
--------------------------------------------------------------------------------
/docs/images/social-media-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oozcitak/xmlbuilder2/723a92bb3dea2334a75e7e227c4c9387a8b8bf8c/docs/images/social-media-banner.png
--------------------------------------------------------------------------------
/docs/js/customscripts.js:
--------------------------------------------------------------------------------
1 | $('#mysidebar').height($(".nav").height());
2 |
3 |
4 | $(document).ready(function () {
5 |
6 | //this script says, if the height of the viewport is greater than 800px, then insert affix class, which makes the nav bar float in a fixed
7 | // position as your scroll. if you have a lot of nav items, this height may not work for you.
8 | var h = $(window).height();
9 | //console.log (h);
10 | if (h > 80000) {
11 | $("#mysidebar").attr("class", "nav affix");
12 | }
13 | // activate tooltips. although this is a bootstrap js function, it must be activated this way in your theme.
14 | $('[data-toggle="tooltip"]').tooltip({
15 | placement: 'top'
16 | });
17 |
18 | /**
19 | * AnchorJS
20 | */
21 | anchors.add('h2,h3,h4,h5');
22 |
23 | });
24 |
25 | // needed for nav tabs on pages. See Formatting > Nav tabs for more details.
26 | // script from http://stackoverflow.com/questions/10523433/how-do-i-keep-the-current-tab-active-with-twitter-bootstrap-after-a-page-reload
27 | $(function () {
28 | var json, tabsState;
29 | $('a[data-toggle="pill"], a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
30 | var href, json, parentId, tabsState;
31 |
32 | tabsState = localStorage.getItem("tabs-state");
33 | json = JSON.parse(tabsState || "{}");
34 | parentId = $(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id");
35 | href = $(e.target).attr('href');
36 | json[parentId] = href;
37 |
38 | return localStorage.setItem("tabs-state", JSON.stringify(json));
39 | });
40 |
41 | tabsState = localStorage.getItem("tabs-state");
42 | json = JSON.parse(tabsState || "{}");
43 |
44 | $.each(json, function (containerId, href) {
45 | return $("#" + containerId + " a[href=" + href + "]").tab('show');
46 | });
47 |
48 | $("ul.nav.nav-pills, ul.nav.nav-tabs").each(function () {
49 | var $this = $(this);
50 | if (!json[$this.attr("id")]) {
51 | return $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first").tab("show");
52 | }
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/docs/js/jquery.ba-throttle-debounce.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery throttle / debounce - v1.1 - 3/7/2010
3 | * http://benalman.com/projects/jquery-throttle-debounce-plugin/
4 | *
5 | * Copyright (c) 2010 "Cowboy" Ben Alman
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://benalman.com/about/license/
8 | */
9 | (function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
--------------------------------------------------------------------------------
/docs/js/jquery.navgoco.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Navgoco Menus Plugin v0.2.1 (2014-04-11)
3 | * https://github.com/tefra/navgoco
4 | *
5 | * Copyright (c) 2014 Chris T (@tefra)
6 | * BSD - https://github.com/tefra/navgoco/blob/master/LICENSE-BSD
7 | */
8 | !function(a){"use strict";var b=function(b,c,d){return this.el=b,this.$el=a(b),this.options=c,this.uuid=this.$el.attr("id")?this.$el.attr("id"):d,this.state={},this.init(),this};b.prototype={init:function(){var b=this;b._load(),b.$el.find("ul").each(function(c){var d=a(this);d.attr("data-index",c),b.options.save&&b.state.hasOwnProperty(c)?(d.parent().addClass(b.options.openClass),d.show()):d.parent().hasClass(b.options.openClass)?(d.show(),b.state[c]=1):d.hide()});var c=a("
").prepend(b.options.caretHtml),d=b.$el.find("li > a");b._trigger(c,!1),b._trigger(d,!0),b.$el.find("li:has(ul) > a").prepend(c)},_trigger:function(b,c){var d=this;b.on("click",function(b){b.stopPropagation();var e=c?a(this).next():a(this).parent().next(),f=!1;if(c){var g=a(this).attr("href");f=void 0===g||""===g||"#"===g}if(e=e.length>0?e:!1,d.options.onClickBefore.call(this,b,e),!c||e&&f)b.preventDefault(),d._toggle(e,e.is(":hidden")),d._save();else if(d.options.accordion){var h=d.state=d._parents(a(this));d.$el.find("ul").filter(":visible").each(function(){var b=a(this),c=b.attr("data-index");h.hasOwnProperty(c)||d._toggle(b,!1)}),d._save()}d.options.onClickAfter.call(this,b,e)})},_toggle:function(b,c){var d=this,e=b.attr("data-index"),f=b.parent();if(d.options.onToggleBefore.call(this,b,c),c){if(f.addClass(d.options.openClass),b.slideDown(d.options.slide),d.state[e]=1,d.options.accordion){var g=d.state=d._parents(b);g[e]=d.state[e]=1,d.$el.find("ul").filter(":visible").each(function(){var b=a(this),c=b.attr("data-index");g.hasOwnProperty(c)||d._toggle(b,!1)})}}else f.removeClass(d.options.openClass),b.slideUp(d.options.slide),d.state[e]=0;d.options.onToggleAfter.call(this,b,c)},_parents:function(b,c){var d={},e=b.parent(),f=e.parents("ul");return f.each(function(){var b=a(this),e=b.attr("data-index");return e?void(d[e]=c?b:1):!1}),d},_save:function(){if(this.options.save){var b={};for(var d in this.state)1===this.state[d]&&(b[d]=1);c[this.uuid]=this.state=b,a.cookie(this.options.cookie.name,JSON.stringify(c),this.options.cookie)}},_load:function(){if(this.options.save){if(null===c){var b=a.cookie(this.options.cookie.name);c=b?JSON.parse(b):{}}this.state=c.hasOwnProperty(this.uuid)?c[this.uuid]:{}}},toggle:function(b){var c=this,d=arguments.length;if(1>=d)c.$el.find("ul").each(function(){var d=a(this);c._toggle(d,b)});else{var e,f={},g=Array.prototype.slice.call(arguments,1);d--;for(var h=0;d>h;h++){e=g[h];var i=c.$el.find('ul[data-index="'+e+'"]').first();if(i&&(f[e]=i,b)){var j=c._parents(i,!0);for(var k in j)f.hasOwnProperty(k)||(f[k]=j[k])}}for(e in f)c._toggle(f[e],b)}c._save()},destroy:function(){a.removeData(this.$el),this.$el.find("li:has(ul) > a").unbind("click"),this.$el.find("li:has(ul) > a > span").unbind("click")}},a.fn.navgoco=function(c){if("string"==typeof c&&"_"!==c.charAt(0)&&"init"!==c)var d=!0,e=Array.prototype.slice.call(arguments,1);else c=a.extend({},a.fn.navgoco.defaults,c||{}),a.cookie||(c.save=!1);return this.each(function(f){var g=a(this),h=g.data("navgoco");h||(h=new b(this,d?a.fn.navgoco.defaults:c,f),g.data("navgoco",h)),d&&h[c].apply(h,e)})};var c=null;a.fn.navgoco.defaults={caretHtml:"",accordion:!1,openClass:"open",save:!0,cookie:{name:"navgoco",expires:!1,path:"/"},slide:{duration:400,easing:"swing"},onClickBefore:a.noop,onClickAfter:a.noop,onToggleBefore:a.noop,onToggleAfter:a.noop}}(jQuery);
--------------------------------------------------------------------------------
/docs/js/toc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/ghiculescu/jekyll-table-of-contents
2 | (function($){
3 | $.fn.toc = function(options) {
4 | var defaults = {
5 | noBackToTopLinks: false,
6 | title: '',
7 | minimumHeaders: 3,
8 | headers: 'h1, h2, h3, h4',
9 | listType: 'ol', // values: [ol|ul]
10 | showEffect: 'show', // values: [show|slideDown|fadeIn|none]
11 | showSpeed: 'slow' // set to 0 to deactivate effect
12 | },
13 | settings = $.extend(defaults, options);
14 |
15 | var headers = $(settings.headers).filter(function() {
16 | // get all headers with an ID
17 | var previousSiblingName = $(this).prev().attr( "name" );
18 | if (!this.id && previousSiblingName) {
19 | this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") );
20 | }
21 | return this.id;
22 | }), output = $(this);
23 | if (!headers.length || headers.length < settings.minimumHeaders || !output.length) {
24 | return;
25 | }
26 |
27 | if (0 === settings.showSpeed) {
28 | settings.showEffect = 'none';
29 | }
30 |
31 | var render = {
32 | show: function() { output.hide().html(html).show(settings.showSpeed); },
33 | slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); },
34 | fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); },
35 | none: function() { output.html(html); }
36 | };
37 |
38 | var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }
39 | var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0];
40 | var return_to_top = '
';
41 |
42 | var level = get_level(headers[0]),
43 | this_level,
44 | html = settings.title + " <"+settings.listType+">";
45 | headers.on('click', function() {
46 | if (!settings.noBackToTopLinks) {
47 | window.location.hash = this.id;
48 | }
49 | })
50 | .addClass('clickable-header')
51 | .each(function(_, header) {
52 | this_level = get_level(header);
53 | if (!settings.noBackToTopLinks && this_level === highest_level) {
54 | $(header).addClass('top-level-header').after(return_to_top);
55 | }
56 | if (this_level === level) // same level as before; same indenting
57 | html += "
" + header.innerHTML + " ";
58 | else if (this_level <= level){ // higher level than before; end parent ol
59 | for(i = this_level; i < level; i++) {
60 | html += ""+settings.listType+">"
61 | }
62 | html += "
" + header.innerHTML + " ";
63 | }
64 | else if (this_level > level) { // lower level than before; expand the previous to contain a ol
65 | for(i = this_level; i > level; i--) {
66 | html += "<"+settings.listType+">"
67 | }
68 | html += "" + header.innerHTML + " ";
69 | }
70 | level = this_level; // update for the next one
71 | });
72 | html += ""+settings.listType+">";
73 | if (!settings.noBackToTopLinks) {
74 | $(document).on('click', '.back-to-top', function() {
75 | $(window).scrollTop(0);
76 | window.location.hash = '';
77 | });
78 | }
79 |
80 | render[settings.showEffect]();
81 | };
82 | })(jQuery);
--------------------------------------------------------------------------------
/docs/licenses/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Tom Johnson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/licenses/LICENSE-BSD-NAVGOCO.txt:
--------------------------------------------------------------------------------
1 | /* This license pertains to the Navgoco jQuery component used for the sidebar. */
2 |
3 | Copyright (c) 2013, Christodoulos Tsoulloftas, http://www.komposta.net
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 | * Neither the name of the nor the names of its
15 | contributors may be used to endorse or promote products derived from this
16 | software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/docs/pages/conversion-functions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Conversion Functions"
3 | keywords: node conversion serialization function api
4 | sidebar: api_sidebar
5 | permalink: conversion-functions.html
6 | toc: false
7 | comments: false
8 | ---
9 |
10 | Following functions can be used to convert an XML document into a string or an
11 | object. See
12 | [serialization settings]({{ site.baseurl }}{% link pages/serialization.md %}#serialization-settings)
13 | page for the settings object used by these functions.
14 |
15 | {% capture cb_note %}
16 | `end` function converts the _entire_ XML document, where `toString` and `toObject` functions convert only the node they are called with.
17 | {% endcapture %}
18 | {% include note.html content=cb_note markdown=1 %}
19 |
20 | ### end
21 |
22 | Converts the entire XML document into its string or object representation. `end`
23 | can be called from anywhere in the document.
24 |
25 |
26 | end (options
?: object)
27 |
28 |
29 | * `options` - serialization options (optional)
30 |
31 | ```js
32 | const { create } = require('xmlbuilder2');
33 |
34 | const doc = create()
35 | .ele('root', { 'att', 'val' })
36 | .ele('foo')
37 | .ele('bar').txt('foobar')
38 | .up()
39 | .ele('baz')
40 | .doc();
41 | console.log(doc.end({ prettyPrint: true }));
42 | ```
43 | ```xml
44 |
45 |
46 |
47 | foobar
48 |
49 |
50 |
51 | ```
52 |
53 |
54 |
55 | ___
56 |
57 | ### toObject
58 |
59 | Converts the node into its object representation.
60 |
61 |
62 | toObject (options
?: object)
63 |
64 |
65 | * `options` - serialization options (optional)
66 |
67 | ```js
68 | const { create } = require('xmlbuilder2');
69 |
70 | const doc = create()
71 | .ele('root', { 'att', 'val' })
72 | .ele('foo')
73 | .ele('bar').txt('foobar')
74 | .up()
75 | .ele('baz')
76 | .doc();
77 | const foo = doc.first().first();
78 | console.log(foo.toObject());
79 | ```
80 | ```js
81 | {
82 | foo: {
83 | bar: 'foobar'
84 | }
85 | }
86 | ```
87 |
88 |
89 |
90 | ___
91 |
92 | ### toString
93 |
94 | Converts the node into its string representation.
95 |
96 |
97 | toString (options
?: object)
98 |
99 |
100 | * `options` - serialization options (optional)
101 |
102 | ```js
103 | const { create } = require('xmlbuilder2');
104 |
105 | const doc = create()
106 | .ele('root', { 'att', 'val' })
107 | .ele('foo')
108 | .ele('bar').txt('foobar')
109 | .up()
110 | .ele('baz')
111 | .doc();
112 | const foo = doc.first().first();
113 | console.log(foo.toString({ prettyPrint: true }));
114 | ```
115 | ```xml
116 |
117 | foobar
118 |
119 | ```
120 |
121 |
122 |
--------------------------------------------------------------------------------
/docs/pages/dom-interfaces.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "DOM Interfaces"
3 | keywords: dom interface
4 | sidebar: api_sidebar
5 | permalink: dom-interfaces.html
6 | toc: false
7 | comments: false
8 | ---
9 | Each node created by `xmlbuilder2` is a DOM node. If required, DOM interfaces can be accessed with the `node` property of the builder object. For example:
10 |
11 | ```js
12 | const { create } = require('xmlbuilder2');
13 |
14 | const child = create().ele('root').ele('child');
15 | const tagName = child.node.tagName;
16 | ```
17 | The `node` property exposes the DOM [Node](https://dom.spec.whatwg.org/#interface-node) interface.
18 |
--------------------------------------------------------------------------------
/docs/pages/other-functions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Other Functions
3 | keywords: functions
4 | sidebar: api_sidebar
5 | permalink: other-functions.html
6 | toc: false
7 | comments: false
8 | ---
9 |
10 | ### set
11 |
12 | Changes builder options. See [builder options]({{ site.baseurl }}{% link pages/builder-functions.md %}#builder-options)
13 | for the options argument.
14 |
15 |
16 | set (options
: object)
17 |
18 |
19 | * `options` - builder options
20 |
21 |
22 |
23 | ### node (property)
24 |
25 | Returns the DOM node wrapped by `xmlbuilder2`.
26 |
27 | {% include warning.html content="`node` is a _property_; not a function." %}
28 |
29 |
30 | node
31 |
32 |
33 | ```js
34 | const { create } = require('xmlbuilder2');
35 |
36 | const ele = create().ele('http:/example.com', 'root');
37 | console.log(ele.node.namespaceURI); // 'http:/example.com'
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/docs/pages/traversal-functions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Traversal Functions"
3 | keywords: node traversal function api
4 | sidebar: api_sidebar
5 | permalink: traversal-functions.html
6 | toc: false
7 | comments: false
8 | ---
9 |
10 | Following functions are used to traverse the document tree.
11 |
12 | ### doc
13 |
14 | Returns the document node. `doc` can be called from anywhere in the document.
15 |
16 |
17 | doc ()
18 |
19 |
20 | ```js
21 | const { create } = require('xmlbuilder2');
22 |
23 | const root = create().ele("root");
24 | const doc = root.doc();
25 | ```
26 |
27 |
28 |
29 | ___
30 |
31 | ### first
32 |
33 | Returns the first child node.
34 |
35 |
36 | first ()
37 |
38 |
39 | ```js
40 | const { create } = require('xmlbuilder2');
41 |
42 | const root = create().ele("root")
43 | .ele("node1").up()
44 | .ele("node2").up();
45 | const node1 = root.first();
46 | ```
47 |
48 |
49 |
50 | ___
51 |
52 | ### last
53 |
54 | Returns the last child node.
55 |
56 |
57 | last ()
58 |
59 |
60 | ```js
61 | const { create } = require('xmlbuilder2');
62 |
63 | const root = create().ele("root")
64 | .ele("node1").up()
65 | .ele("node2").up();
66 | const node2 = root.last();
67 | ```
68 |
69 |
70 |
71 | ___
72 |
73 | ### next
74 |
75 | Returns the next sibling node.
76 |
77 |
78 | next ()
79 |
80 |
81 | ```js
82 | const { create } = require('xmlbuilder2');
83 |
84 | const root = create().ele("root")
85 | .ele("node1").up()
86 | .ele("node2").up();
87 | const node1 = root.first();
88 | const node2 = node1.next();
89 | ```
90 |
91 |
92 |
93 | ___
94 |
95 | ### prev
96 |
97 | Returns the previous sibling node.
98 |
99 |
100 | prev ()
101 |
102 |
103 | ```js
104 | const { create } = require('xmlbuilder2');
105 |
106 | const root = create().ele("root")
107 | .ele("node1").up()
108 | .ele("node2").up();
109 | const node2 = root.last();
110 | const node1 = node2.prev();
111 | ```
112 |
113 |
114 |
115 | ___
116 |
117 | ### root
118 |
119 | Returns the root element node. Root element node is the document element node of
120 | the XML document. `root` can be called from anywhere in the document.
121 |
122 |
123 | root ()
124 |
125 |
126 | ```js
127 | const { create } = require('xmlbuilder2');
128 |
129 | const grandChild = create().ele("root").ele("child").ele("grandchild");
130 | const root = grandchild.root();
131 | ```
132 |
133 |
134 |
135 | ___
136 |
137 | ### up
138 |
139 | Returns the parent element node.
140 |
141 |
142 | up ()
143 |
144 |
145 | ```js
146 | const { create } = require('xmlbuilder2');
147 |
148 | const grandChild = create().ele("root").ele("child").ele("grandchild");
149 | const child = grandchild.up();
150 | const root = child.up();
151 | ```
152 |
153 |
154 |
--------------------------------------------------------------------------------
/docs/pages/using-with-external-libraries.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Using with External Libraries"
3 | keywords: external library
4 | sidebar: api_sidebar
5 | permalink: using-with-external-libraries.html
6 | toc: false
7 | comments: false
8 | ---
9 | Since `xmlbuilder2` implements the DOM specification, it should be readily usable with any external library compatible with DOM interfaces.
10 |
11 | ### xpath
12 |
13 | For example, by using the [`xpath`](https://github.com/goto100/xpath) module:
14 |
15 | ```js
16 | const { create } = require('xmlbuilder2');
17 | const { select } = require('xpath');
18 |
19 | const doc = create("The Book ");
20 | const nodes = select("//title", doc.node);
21 |
22 | console.log(nodes[0].localName); // "title"
23 | console.log(nodes[0].firstChild.data); // "The Book"
24 | console.log(nodes[0].toString()); // "The Book "
25 | ```
26 |
27 | Namespaces are supported:
28 | ```js
29 | const { create } = require('xmlbuilder2');
30 | const { select } = require('xpath');
31 |
32 | const doc = create("Harry Potter ")
33 | const node = select("//*[local-name(.)='title' and namespace-uri(.)='myns']", doc.node)
34 |
35 | console.log(node[0].namespaceURI); // "myns"
36 | ```
37 |
38 | ### libxmljs
39 |
40 | Validating against an XSD by using the [`libxmljs`](https://github.com/libxmljs/libxmljs) module:
41 |
42 | ```js
43 | const { create } = require('xmlbuilder2');
44 | const { parseXml } = require('libxmljs');
45 |
46 | // create our schema
47 | const xsdDoc = create()
48 | .ele('xs:schema', { 'xmlns:xs': 'http://www.w3.org/2001/XMLSchema' })
49 | .ele('xs:element', { name: 'book' })
50 | .doc();
51 | // and our document
52 | const xmlDoc = create().ele('book').doc();
53 |
54 | // parse and validate with libxml
55 | const xsd = parseXml(xsdDoc.end());
56 | const xml = parseXml(xmlDoc.end());
57 |
58 | const result = xml.validate(xsd); // true
59 | ```
60 |
61 | {% capture ts_tip %}
62 | `XMLBuilder2` uses its own TypeScript interfaces for DOM nodes; which typically will not be compatible with the interfaces exported by other libraries. TypeScript users should cast those interfaces accordingly to prevent TS 2345 errors.
63 | {% endcapture %}
64 | {% include warning.html content=ts_tip %}
65 |
--------------------------------------------------------------------------------
/docs/search.json:
--------------------------------------------------------------------------------
1 | ---
2 | title: search
3 | layout: none
4 | search: exclude
5 | ---
6 |
7 | [
8 | {% for page in site.pages %}
9 | {% unless page.search == "exclude" %}
10 | {
11 | "title": "{{ page.title | escape }}",
12 | "tags": "{{ page.tags }}",
13 | "keywords": "{{page.keywords}}",
14 | "url": "{{ page.url | remove: "/"}}",
15 | "summary": "{{page.summary | strip }}"
16 | }
17 | {% unless forloop.last and site.posts.size < 1 %},{% endunless %}
18 | {% endunless %}
19 | {% endfor %}
20 |
21 | {% for post in site.posts %}
22 |
23 | {
24 | "title": "{{ post.title | escape }}",
25 | "tags": "{{ post.tags }}",
26 | "keywords": "{{post.keywords}}",
27 | "url": "{{ post.url | remove: "/" }}",
28 | "summary": "{{post.summary | strip }}"
29 | }
30 | {% unless forloop.last %},{% endunless %}
31 | {% endfor %}
32 |
33 | ]
34 |
--------------------------------------------------------------------------------
/docs/sitemap.xml:
--------------------------------------------------------------------------------
1 | ---
2 | layout: none
3 | search: exclude
4 | ---
5 |
6 |
7 |
8 | {% for post in site.posts %}
9 | {% unless post.search == "exclude" %}
10 |
11 | {{site.url}}{{post.url}}
12 |
13 | {% endunless %}
14 | {% endfor %}
15 |
16 |
17 | {% for page in site.pages %}
18 | {% unless page.search == "exclude" %}
19 |
20 | {{site.url}}{{ page.url}}
21 |
22 | {% endunless %}
23 | {% endfor %}
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xmlbuilder2",
3 | "version": "3.1.1",
4 | "keywords": [
5 | "xml",
6 | "xmlbuilder"
7 | ],
8 | "homepage": "http://github.com/oozcitak/xmlbuilder2",
9 | "description": "An XML builder for node.js",
10 | "author": "Ozgur Ozcitak ",
11 | "contributors": [],
12 | "license": "MIT",
13 | "repository": {
14 | "type": "git",
15 | "url": "git://github.com/oozcitak/xmlbuilder2.git"
16 | },
17 | "bugs": {
18 | "url": "http://github.com/oozcitak/xmlbuilder2/issues"
19 | },
20 | "main": "./lib/index",
21 | "browser": "./lib/xmlbuilder2.min.js",
22 | "engines": {
23 | "node": ">=12.0"
24 | },
25 | "files": [
26 | "lib/**/*"
27 | ],
28 | "types": "./lib/index.d.ts",
29 | "dependencies": {
30 | "@oozcitak/dom": "1.15.10",
31 | "@oozcitak/infra": "1.0.8",
32 | "@oozcitak/util": "8.3.8",
33 | "js-yaml": "3.14.1"
34 | },
35 | "devDependencies": {
36 | "@babel/preset-env": "*",
37 | "@babel/runtime-corejs3": "7.10.3",
38 | "@types/benchmark": "*",
39 | "@types/dedent": "*",
40 | "@types/jest": "*",
41 | "@types/js-yaml": "3.11.1",
42 | "@types/node": "*",
43 | "babel-loader": "*",
44 | "benchmark": "*",
45 | "chalk": "*",
46 | "core-js": "3.6.5",
47 | "dedent": "*",
48 | "es6-proxy-polyfill": "*",
49 | "glob": "*",
50 | "harmony-reflect": "*",
51 | "jest": "*",
52 | "libxmljs2": "*",
53 | "ts-jest": "*",
54 | "ts-loader": "*",
55 | "ts-node": "*",
56 | "typescript": "*",
57 | "webpack": "*",
58 | "webpack-cli": "*",
59 | "xmlbuilder": "*",
60 | "xpath": "*"
61 | },
62 | "jest": {
63 | "transform": {
64 | "^.+\\.tsx?$": "ts-jest"
65 | },
66 | "testRegex": "/test/.*\\.test\\.tsx?$",
67 | "testEnvironment": "node",
68 | "collectCoverageFrom": [
69 | "src/**/*.{ts,tsx}"
70 | ]
71 | },
72 | "scripts": {
73 | "prepare": "tsc && webpack",
74 | "pretest": "rm -rf ./lib && tsc --version && tsc && webpack",
75 | "test": "jest --coverage",
76 | "perf": "npm run pretest && ts-node ./perf/perf.ts",
77 | "perf-cb": "npm run pretest && ts-node ./perf/perf-cb.ts",
78 | "prof-serialize": "npm run pretest && rm -f isolate-*-v8.log && node --prof ./perf/prof-serialize.js && find . -name isolate-*-v8.log -exec mv {} isolate-v8.log ; && node --prof-process isolate-v8.log > isolate-serialize.log && rm isolate-v8.log",
79 | "postpublish": "git push --all && git push --tags",
80 | "servedocs": "(cd docs && bundle exec jekyll serve)"
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/perf/perf-cb.ts:
--------------------------------------------------------------------------------
1 | import { createCB } from "../lib"
2 | import { resolve } from "path"
3 | import { createWriteStream, unlink } from "fs"
4 | import { memoryUsage, hrtime } from "process"
5 | import chalk from "chalk"
6 |
7 | (async function () {
8 | const filename = resolve(__dirname, 'stream-perf.log')
9 | const outFile = createWriteStream(filename)
10 |
11 | const xmlStream = createCB({
12 | data: (chunk) => outFile.write(chunk),
13 | end: () => {
14 | outFile.close()
15 | unlink(filename, () => { })
16 | },
17 | error: (err) => { throw err },
18 | prettyPrint: true
19 | })
20 |
21 | console.log(`${chalk.bold.underline(`Callback API Benchmark`)}`)
22 | let maxMem = 0
23 | const t0 = hrtime.bigint()
24 | outFile.on("close", () => {
25 | const t2 = hrtime.bigint()
26 | console.log("Completed writing to disk in " + (Number(t2 - t1) / 1000000).toFixed(0) + " ms")
27 | console.log("Maximum heap memory used is " + (maxMem / 1024 / 1024).toFixed(2) + " MB")
28 | })
29 |
30 | xmlStream.ele("root")
31 | for (let n = 0; n < 10; n++) {
32 | const heap = memoryUsage().heapUsed
33 | if (heap > maxMem) maxMem = heap
34 | const mem = (heap / 1024 / 1024).toFixed(2)
35 | console.log(` ${n + 1}: ${mem} MB`)
36 | xmlStream.ele("node").att("id", n.toString())
37 | for (let i = 0; i < 10000; i++) {
38 | xmlStream.ele("foo").att("id", i.toString()).txt("lorem ipsum").up()
39 | }
40 | xmlStream.up()
41 | }
42 | xmlStream.end()
43 | const t1 = hrtime.bigint()
44 | console.log("Completed serialization in " + (Number(t1 - t0) / 1000000).toFixed(0) + " ms")
45 | })()
46 |
--------------------------------------------------------------------------------
/perf/prof-serialize.js:
--------------------------------------------------------------------------------
1 | const { create } = require("../lib")
2 |
3 | const doc = create()
4 | const root = doc.ele("root")
5 | for (let i = 0; i < 100; i++) {
6 | const node = root.ele("node" + i.toString())
7 | for (let j = 0; j < 10; j++) {
8 | node.att("att" + j.toString(), "val" + j.toString())
9 | node.txt("text" + j.toString())
10 | }
11 | }
12 | for (let i = 0; i < 10000; i++) {
13 | doc.end({ prettyPrint: true })
14 | }
15 |
--------------------------------------------------------------------------------
/src/builder/BuilderFunctionsCB.ts:
--------------------------------------------------------------------------------
1 | import { XMLBuilderCB, XMLBuilderCBCreateOptions } from '../interfaces'
2 | import { XMLBuilderCBImpl } from '.'
3 |
4 | /**
5 | * Creates an XML builder which serializes the document in chunks.
6 | *
7 | * @param options - callback builder options
8 | *
9 | * @returns callback builder
10 | */
11 | export function createCB(options?: XMLBuilderCBCreateOptions): XMLBuilderCB {
12 | return new XMLBuilderCBImpl(options)
13 | }
14 |
15 | /**
16 | * Creates an XML builder which serializes the fragment in chunks.
17 | *
18 | * @param options - callback builder options
19 | *
20 | * @returns callback builder
21 | */
22 | export function fragmentCB(options?: XMLBuilderCBCreateOptions): XMLBuilderCB {
23 | return new XMLBuilderCBImpl(options, true)
24 | }
25 |
--------------------------------------------------------------------------------
/src/builder/dom.ts:
--------------------------------------------------------------------------------
1 | import { Document } from "@oozcitak/dom/lib/dom/interfaces"
2 | import { DOMImplementation } from "@oozcitak/dom"
3 | import { dom } from "@oozcitak/dom/lib/dom"
4 | import { isString } from '@oozcitak/util'
5 |
6 | dom.setFeatures(false)
7 |
8 | /**
9 | * Creates an XML document without any child nodes.
10 | */
11 | export function createDocument(): Document {
12 | const impl = new DOMImplementation()
13 | const doc = impl.createDocument(null, 'root', null)
14 | /* istanbul ignore else */
15 | if (doc.documentElement) {
16 | doc.removeChild(doc.documentElement)
17 | }
18 | return doc
19 | }
20 |
21 | export function sanitizeInput(str: string,
22 | replacement?: string | ((char: string, offset: number, str: string) => string)): string
23 | export function sanitizeInput(str: string | null,
24 | replacement?: string | ((char: string, offset: number, str: string) => string)): string | null
25 | export function sanitizeInput(str: string | null | undefined,
26 | replacement?: string | ((char: string, offset: number, str: string) => string)): string | null | undefined
27 |
28 | /**
29 | * Sanitizes input strings with user supplied replacement characters.
30 | *
31 | * @param str - input string
32 | * @param replacement - replacement character or function
33 | */
34 | export function sanitizeInput(str: any,
35 | replacement?: string | ((char: string, offset: number, str: string) => string)): any {
36 | if (str == null) {
37 | return str
38 | } else if (replacement === undefined) {
39 | return str + ""
40 | } else {
41 | let result = ""
42 | str = str + ""
43 | for (let i = 0; i < str.length; i++) {
44 | let n = str.charCodeAt(i)
45 |
46 | // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
47 | if (n === 0x9 || n === 0xA || n === 0xD ||
48 | (n >= 0x20 && n <= 0xD7FF) ||
49 | (n >= 0xE000 && n <= 0xFFFD)) {
50 | // valid character - not surrogate pair
51 | result += str.charAt(i)
52 | } else if (n >= 0xD800 && n <= 0xDBFF && i < str.length - 1) {
53 | const n2 = str.charCodeAt(i + 1)
54 | if (n2 >= 0xDC00 && n2 <= 0xDFFF) {
55 | // valid surrogate pair
56 | n = (n - 0xD800) * 0x400 + n2 - 0xDC00 + 0x10000
57 | result += String.fromCodePoint(n)
58 | i++
59 | } else {
60 | // invalid lone surrogate
61 | result += isString(replacement) ? replacement : replacement(str.charAt(i), i, str)
62 | }
63 | } else {
64 | // invalid character
65 | result += isString(replacement) ? replacement : replacement(str.charAt(i), i, str)
66 | }
67 | }
68 |
69 | return result
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/builder/index.ts:
--------------------------------------------------------------------------------
1 | export { XMLBuilderImpl } from "./XMLBuilderImpl"
2 | export { XMLBuilderCBImpl } from "./XMLBuilderCBImpl"
3 | export { builder, create, fragment, convert } from "./BuilderFunctions"
4 | export { createCB, fragmentCB } from "./BuilderFunctionsCB"
5 |
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const nonEntityAmpersandRegex = /&(?![A-Za-z]+;|#\d+;)/g;
2 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { builder, create, fragment, convert, createCB, fragmentCB } from "./builder"
2 |
--------------------------------------------------------------------------------
/src/readers/JSONReader.ts:
--------------------------------------------------------------------------------
1 | import { XMLBuilder } from "../interfaces"
2 | import { ObjectReader } from "./ObjectReader"
3 | import { BaseReader } from "./BaseReader"
4 |
5 | /**
6 | * Parses XML nodes from a JSON string.
7 | */
8 | export class JSONReader extends BaseReader {
9 |
10 | /**
11 | * Parses the given document representation.
12 | *
13 | * @param node - node receive parsed XML nodes
14 | * @param str - JSON string to parse
15 | */
16 | _parse(node: XMLBuilder, str: string): XMLBuilder {
17 | return new ObjectReader(this._builderOptions).parse(node, JSON.parse(str))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/readers/YAMLReader.ts:
--------------------------------------------------------------------------------
1 | import { XMLBuilder } from "../interfaces"
2 | import { ObjectReader } from "./ObjectReader"
3 | import { BaseReader } from "./BaseReader"
4 | import { safeLoad } from "js-yaml"
5 |
6 | /**
7 | * Parses XML nodes from a YAML string.
8 | */
9 | export class YAMLReader extends BaseReader {
10 |
11 | /**
12 | * Parses the given document representation.
13 | *
14 | * @param node - node receive parsed XML nodes
15 | * @param str - YAML string to parse
16 | */
17 | _parse(node: XMLBuilder, str: string): XMLBuilder {
18 | const result = safeLoad(str)
19 | /* istanbul ignore next */
20 | if (result === undefined) {
21 | throw new Error("Unable to parse YAML document.")
22 | }
23 | return new ObjectReader(this._builderOptions).parse(node, result)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/readers/index.ts:
--------------------------------------------------------------------------------
1 | export { XMLReader } from './XMLReader'
2 | export { ObjectReader } from './ObjectReader'
3 | export { JSONReader } from './JSONReader'
4 | export { YAMLReader } from './YAMLReader'
5 |
--------------------------------------------------------------------------------
/src/writers/MapWriter.ts:
--------------------------------------------------------------------------------
1 | import {
2 | MapWriterOptions, ObjectWriterOptions, XMLSerializedAsMap,
3 | XMLSerializedAsMapArray, XMLBuilderOptions
4 | } from "../interfaces"
5 | import { applyDefaults, isArray, isObject } from "@oozcitak/util"
6 | import { Node } from "@oozcitak/dom/lib/dom/interfaces"
7 | import { ObjectWriter } from "./ObjectWriter"
8 | import { BaseWriter } from "./BaseWriter"
9 |
10 | /**
11 | * Serializes XML nodes into ES6 maps and arrays.
12 | */
13 | export class MapWriter extends BaseWriter {
14 |
15 | /**
16 | * Initializes a new instance of `MapWriter`.
17 | *
18 | * @param builderOptions - XML builder options
19 | * @param writerOptions - serialization options
20 | */
21 | constructor(builderOptions: XMLBuilderOptions, writerOptions: MapWriterOptions) {
22 | super(builderOptions)
23 | // provide default options
24 | this._writerOptions = applyDefaults(writerOptions, {
25 | format: "map",
26 | wellFormed: false,
27 | group: false,
28 | verbose: false
29 | }) as Required
30 | }
31 |
32 | /**
33 | * Produces an XML serialization of the given node.
34 | *
35 | * @param node - node to serialize
36 | */
37 | serialize(node: Node): XMLSerializedAsMap | XMLSerializedAsMapArray {
38 | // convert to object
39 | const objectWriterOptions: ObjectWriterOptions = applyDefaults(this._writerOptions, {
40 | format: "object",
41 | wellFormed: false,
42 | verbose: false
43 | })
44 | const objectWriter = new ObjectWriter(this._builderOptions, objectWriterOptions)
45 | const val = objectWriter.serialize(node)
46 |
47 | // recursively convert object into Map
48 | return this._convertObject(val)
49 | }
50 |
51 | /**
52 | * Recursively converts a JS object into an ES5 map.
53 | *
54 | * @param obj - a JS object
55 | */
56 | _convertObject(obj: any): any {
57 | if (isArray(obj)) {
58 | for (let i = 0; i < obj.length; i++) {
59 | obj[i] = this._convertObject(obj[i])
60 | }
61 | return obj as any
62 | } else if (isObject(obj)) {
63 | const map = new Map()
64 | for (const key in obj) {
65 | map.set(key, this._convertObject((obj as any)[key]))
66 | }
67 | return map
68 | } else {
69 | return obj
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/writers/index.ts:
--------------------------------------------------------------------------------
1 | export { MapWriter } from './MapWriter'
2 | export { XMLWriter } from './XMLWriter'
3 | export { ObjectWriter } from './ObjectWriter'
4 | export { JSONWriter } from './JSONWriter'
5 | export { YAMLWriter } from './YAMLWriter'
6 |
--------------------------------------------------------------------------------
/test/basic/builder.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { Document, NodeType } from "@oozcitak/dom/lib/dom/interfaces"
3 |
4 | describe('builder()', () => {
5 |
6 | test('wrap node', () => {
7 | const doc = $$.create()
8 | const root = (doc.node as Document).createElement('root')
9 | const builder = $$.builder(root)
10 | const ele = builder.ele('ele')
11 | expect(ele.toString()).toBe(' ')
12 | })
13 |
14 | test('invalid wrapper', () => {
15 | const doc = $$.create()
16 | const root = (doc.node as Document).createElement('root')
17 | expect(() => $$.builder({ version: "1.0" } as any)).toThrow()
18 | })
19 |
20 | test('node', () => {
21 | const node = $$.create().ele('root').ele('node')
22 | expect(node.node.nodeType).toBe(NodeType.Element)
23 | })
24 |
25 | })
26 |
--------------------------------------------------------------------------------
/test/basic/cdata.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('dat()', () => {
4 |
5 | test('basic', () => {
6 | const root = $$.create().ele('root')
7 | const node1 = root.ele('node1')
8 | node1.dat('node1 cdata').ele('node1-2')
9 | const node2 = root.ele('node2')
10 |
11 | expect($$.printTree(root.doc().node)).toBe($$.t`
12 | root
13 | node1
14 | $ node1 cdata
15 | node1-2
16 | node2
17 | `)
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/basic/comment.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('com()', () => {
4 |
5 | test('basic', () => {
6 | const root = $$.create().ele('root')
7 | const node1 = root.ele('node1')
8 | node1.com('node1 comment').ele('node1-2')
9 | const node2 = root.ele('node2')
10 |
11 | expect($$.printTree(root.doc().node)).toBe($$.t`
12 | root
13 | node1
14 | ! node1 comment
15 | node1-2
16 | node2
17 | `)
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/basic/convert.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('convert()', () => {
4 |
5 | const matrix: { [key: string]: any } = {
6 | xml: `text `,
7 | object: { root: { "@att": "val", "#": "text" }},
8 | json: `{"root":{"@att":"val","#":"text"}}`,
9 | map: new Map([["root", new Map([["@att", "val"], ["#", "text" ]])]]),
10 | yaml: $$.t`
11 | ---
12 | "root":
13 | "@att": "val"
14 | "#": "text"
15 | `
16 | }
17 |
18 | test('Conversion matrix', () => {
19 | const formats = Object.keys(matrix)
20 | for (const inputFormat of formats)
21 | {
22 | const input = matrix[inputFormat]
23 | for (const outputFormat of formats)
24 | {
25 | const output = matrix[outputFormat]
26 | expect($$.convert(input, { format: outputFormat})).toEqual(output)
27 | }
28 | }
29 | })
30 |
31 | test('From XML string to XML string with default options', () => {
32 | const xml = $$.convert('text ')
33 | expect(xml).toBe(`text `)
34 | })
35 |
36 | test('Conversion to XML string with options', () => {
37 | const formats = Object.keys(matrix)
38 | for (const inputFormat of formats)
39 | {
40 | const input = matrix[inputFormat]
41 | expect($$.convert({ version: "1.0" }, input, { format: "xml" })).toBe(matrix["xml"])
42 | }
43 | })
44 |
45 | })
46 |
--------------------------------------------------------------------------------
/test/basic/create.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('create()', () => {
4 |
5 | test('Empty document', () => {
6 | const doc = $$.create()
7 | expect($$.printTree(doc.node)).toBe('')
8 | expect(doc.end()).toBe('')
9 | })
10 |
11 | test('Document with root element', () => {
12 | const ele = $$.create().ele('root', { att: "val" }).txt("text")
13 | expect($$.printTree(ele.node)).toBe($$.t`
14 | root att="val"
15 | # text
16 | `)
17 | expect(ele.end()).toBe('text ')
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/basic/declaration.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('dec()', () => {
4 |
5 | test('version', () => {
6 | const doc = $$.create().ele('root').dec({ encoding: "UTF-8" }).doc()
7 | expect(doc.end()).toBe(' ')
8 | })
9 |
10 | test('all params', () => {
11 | const doc = $$.create().ele('root').dec({ version: "1.0", encoding: "UTF-8", standalone: false }).doc()
12 | expect(doc.end()).toBe(' ')
13 | })
14 |
15 | })
16 |
--------------------------------------------------------------------------------
/test/basic/doc.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('fragment()', () => {
4 |
5 | test('doc returns owner document', () => {
6 | const doc = $$.create()
7 | const node = doc.ele('root').ele('node')
8 | expect(node.doc().node).toBe(doc.node)
9 | })
10 |
11 | test('doc returns owner document fragment', () => {
12 | const frag = $$.fragment()
13 | const node = frag.ele('root').ele('node')
14 | expect(node.doc().node).toBe(frag.node)
15 | })
16 |
17 | })
18 |
--------------------------------------------------------------------------------
/test/basic/doctype.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('dtd()', () => {
4 |
5 | test('without identifiers', () => {
6 | const root = $$.create().ele('root').dtd()
7 | expect($$.printTree(root.doc().node)).toBe($$.t`
8 | !DOCTYPE root
9 | root
10 | `)
11 | })
12 |
13 | test('public identifier', () => {
14 | const root = $$.create().ele('root').dtd({ pubID: 'pub' })
15 | expect($$.printTree(root.doc().node)).toBe($$.t`
16 | !DOCTYPE root PUBLIC pub
17 | root
18 | `)
19 | })
20 |
21 | test('system identifier', () => {
22 | const root = $$.create().ele('root').dtd({ sysID: 'sys' })
23 | expect($$.printTree(root.doc().node)).toBe($$.t`
24 | !DOCTYPE root SYSTEM sys
25 | root
26 | `)
27 | })
28 |
29 | test('both identifiers', () => {
30 | const root = $$.create().ele('root').dtd({ pubID: 'pub', sysID: 'sys' })
31 | expect($$.printTree(root.doc().node)).toBe($$.t`
32 | !DOCTYPE root PUBLIC pub sys
33 | root
34 | `)
35 | })
36 |
37 | test('replace doctype', () => {
38 | const root = $$.create().ele('root').dtd({ pubID: "pub", sysID: "sys" })
39 | expect($$.printTree(root.doc().node)).toBe($$.t`
40 | !DOCTYPE root PUBLIC pub sys
41 | root
42 | `)
43 |
44 | root.dtd({ pubID: 'newpub', sysID: 'newsys' })
45 | expect($$.printTree(root.doc().node)).toBe($$.t`
46 | !DOCTYPE root PUBLIC newpub newsys
47 | root
48 | `)
49 | })
50 |
51 | test('name must match document element node', () => {
52 | const doc = $$.create().ele('root')
53 | expect(() => doc.dtd({ name: 'newroot' })).toThrow()
54 | })
55 |
56 | test('update when element node changes', () => {
57 | const doc = $$.create().dtd({ pubID: "pub", sysID: "sys" })
58 | doc.ele('newroot')
59 | expect($$.printTree(doc.node)).toBe($$.t`
60 | !DOCTYPE newroot PUBLIC pub sys
61 | newroot
62 | `)
63 | })
64 |
65 | })
66 |
--------------------------------------------------------------------------------
/test/basic/element.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('ele()', () => {
4 |
5 | test('string name', () => {
6 | const root = $$.create().ele('root')
7 | const node1 = root.ele('node1')
8 | node1.ele('node1-1')
9 | node1.ele('node1-2')
10 | const node2 = root.ele('node2')
11 | node2.ele('node2-1')
12 | node2.ele('node2-2')
13 | node2.ele('node2-3')
14 |
15 | expect($$.printTree(root.doc().node)).toBe($$.t`
16 | root
17 | node1
18 | node1-1
19 | node1-2
20 | node2
21 | node2-1
22 | node2-2
23 | node2-3
24 | `)
25 | })
26 |
27 | test('null name', () => {
28 | expect(() => $$.create().ele(null as any)).toThrow()
29 | })
30 |
31 | test('element namespace cannot be overwritten', () => {
32 | const root = $$.create().ele('ns1', 'root@ns2')
33 | expect((root.node as any).namespaceURI).toBe('ns1')
34 | })
35 |
36 | test('from JS object', () => {
37 | const root = $$.create().ele('root')
38 | root.ele({
39 | 'node1': { 'node1-1': '', 'node1-2': '' },
40 | 'node2': { 'node2-1': '', 'node2-2': '', 'node2-3': '' }
41 | })
42 |
43 | expect($$.printTree(root.doc().node)).toBe($$.t`
44 | root
45 | node1
46 | node1-1
47 | node1-2
48 | node2
49 | node2-1
50 | node2-2
51 | node2-3
52 | `)
53 | })
54 |
55 | test('from XML string', () => {
56 | const root = $$.create().ele('root')
57 | root.ele(' ')
58 |
59 | expect($$.printTree(root.doc().node)).toBe($$.t`
60 | root
61 | node1
62 | node1-1
63 | node1-2
64 | node2
65 | node2-1
66 | node2-2
67 | node2-3
68 | `)
69 | })
70 |
71 | test('from JSON string', () => {
72 | const root = $$.create().ele('root')
73 | root.ele(`{
74 | "node1": { "node1-1": "", "node1-2": "" },
75 | "node2": { "node2-1": "", "node2-2": "", "node2-3": "" }
76 | }`)
77 | expect($$.printTree(root.doc().node)).toBe($$.t`
78 | root
79 | node1
80 | node1-1
81 | node1-2
82 | node2
83 | node2-1
84 | node2-2
85 | node2-3
86 | `)
87 | })
88 |
89 | })
90 |
--------------------------------------------------------------------------------
/test/basic/end.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('end()', () => {
4 |
5 | test('simple document', () => {
6 | const xml = $$.create()
7 | .dtd({ pubID: "pub", sysID: "sys" })
8 | .ele('root')
9 | .com('comment')
10 | .ins('target', 'content')
11 | .dat('cdata node')
12 | .txt('some text')
13 | .ele('node', {att: 'val', att2: 'val2'})
14 | .txt('more text')
15 | .end()
16 |
17 | expect(xml).toBe(
18 | '' +
19 | '' +
20 | '' +
21 | '' +
22 | '' +
23 | '' +
24 | 'some text' +
25 | '' +
26 | 'more text' +
27 | ' ' +
28 | ' '
29 | )
30 | })
31 |
32 | test('invalid writer format', () => {
33 | const xml = $$.create() as any
34 | expect(() => xml.end({ format: "invalid" })).toThrow()
35 | })
36 |
37 | })
38 |
--------------------------------------------------------------------------------
/test/basic/fragment.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('fragment()', () => {
4 |
5 | test('ele', () => {
6 | const frag = $$.fragment()
7 | const node1 = frag.ele('node1')
8 | const node2 = frag.ele('node2')
9 | node1.ele('node1-1').att("att1-1", "val1-1")
10 | node1.ele('node1-2').att("att1-2", "val1-2")
11 | node2.ele('node2-1').att("att2-1", "val2-1")
12 | node2.ele('node2-2').att("att2-2", "val2-2")
13 | expect($$.printTree(frag.node)).toBe($$.t`
14 | node1
15 | node1-1 att1-1="val1-1"
16 | node1-2 att1-2="val1-2"
17 | node2
18 | node2-1 att2-1="val2-1"
19 | node2-2 att2-2="val2-2"
20 | `)
21 | })
22 |
23 | test('JS object', () => {
24 | const obj = {
25 | node1: {
26 | "node1-1": { "@att1-1": "val1-1" },
27 | "node1-2": { "@att1-2": "val1-2" }
28 | },
29 | node2: {
30 | "node2-1": { "@att2-1": "val2-1" },
31 | "node2-2": { "@att2-2": "val2-2" }
32 | }
33 | }
34 | const frag = $$.fragment(obj)
35 | expect($$.printTree(frag.node)).toBe($$.t`
36 | node1
37 | node1-1 att1-1="val1-1"
38 | node1-2 att1-2="val1-2"
39 | node2
40 | node2-1 att2-1="val2-1"
41 | node2-2 att2-2="val2-2"
42 | `)
43 | })
44 |
45 | test('JS object with array', () => {
46 | const obj = [
47 | { node1: "val1" },
48 | { node2: "val2" }
49 | ]
50 | const frag = $$.fragment(obj)
51 | expect($$.printTree(frag.node)).toBe($$.t`
52 | node1
53 | # val1
54 | node2
55 | # val2
56 | `)
57 | const root = $$.create().ele("root")
58 | root.import(frag)
59 | expect($$.printTree(root.node)).toBe($$.t`
60 | root
61 | node1
62 | # val1
63 | node2
64 | # val2
65 | `)
66 | })
67 |
68 | test('JSON string', () => {
69 | const obj = {
70 | node1: {
71 | "node1-1": { "@att1-1": "val1-1" },
72 | "node1-2": { "@att1-2": "val1-2" }
73 | },
74 | node2: {
75 | "node2-1": { "@att2-1": "val2-1" },
76 | "node2-2": { "@att2-2": "val2-2" }
77 | }
78 | }
79 | const frag = $$.fragment(JSON.stringify(obj))
80 | expect($$.printTree(frag.node)).toBe($$.t`
81 | node1
82 | node1-1 att1-1="val1-1"
83 | node1-2 att1-2="val1-2"
84 | node2
85 | node2-1 att2-1="val2-1"
86 | node2-2 att2-2="val2-2"
87 | `)
88 | })
89 |
90 | test('XML string', () => {
91 | const str = $$.t`
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | `
101 | const frag = $$.fragment(str)
102 | expect($$.printTree(frag.node)).toBe($$.t`
103 | node1
104 | node1-1 att1-1="val1-1"
105 | node1-2 att1-2="val1-2"
106 | node2
107 | node2-1 att2-1="val2-1"
108 | node2-2 att2-2="val2-2"
109 | `)
110 | })
111 |
112 | test('end', () => {
113 | const frag = $$.fragment()
114 | const node1 = frag.ele('node1')
115 | const node2 = frag.ele('node2')
116 | node1.ele('node1-1').att("att1-1", "val1-1")
117 | node1.ele('node1-2').att("att1-2", "val1-2")
118 | node2.ele('node2-1').att("att2-1", "val2-1")
119 | node2.ele('node2-2').att("att2-2", "val2-2")
120 | expect(frag.end( { prettyPrint: true })).toBe($$.t`
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | `)
130 | })
131 |
132 | })
133 |
--------------------------------------------------------------------------------
/test/basic/instruction.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('ins()', () => {
4 |
5 | test('basic', () => {
6 | const root = $$.create().ele('root')
7 | const node1 = root.ele('node1')
8 | node1.ins('target1', 'content').ele('node1-2')
9 | const node2 = root.ele('node2')
10 | node2.ins('target2')
11 |
12 | expect($$.printTree(root.doc().node)).toBe($$.t`
13 | root
14 | node1
15 | ? target1 content
16 | node1-2
17 | node2
18 | ? target2
19 | `)
20 | })
21 |
22 | test('array', () => {
23 | const root = $$.create().ele('root')
24 | root.ins(['target1 content', 'target2'])
25 |
26 | expect($$.printTree(root.doc().node)).toBe($$.t`
27 | root
28 | ? target1 content
29 | ? target2
30 | `)
31 | })
32 |
33 | test('object', () => {
34 | const root = $$.create().ele('root')
35 | root.ins({ target1: 'content', target2: '' })
36 |
37 | expect($$.printTree(root.doc().node)).toBe($$.t`
38 | root
39 | ? target1 content
40 | ? target2
41 | `)
42 | })
43 |
44 | })
45 |
--------------------------------------------------------------------------------
/test/basic/options.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('options()', () => {
4 |
5 | test('get encoding', () => {
6 | const doc = $$.create({ encoding: "Shift-JIS" }).ele('root').doc()
7 | expect(doc.options.encoding).toBe('Shift-JIS')
8 | })
9 |
10 | test('set encoding', () => {
11 | const doc = $$.create({ encoding: "UTF-8" }).ele('root')
12 | .set({ encoding: "Shift-JIS" }).doc()
13 | expect(doc.end()).toBe(' ')
14 | })
15 |
16 | })
17 |
--------------------------------------------------------------------------------
/test/basic/parse.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('parse()', () => {
4 |
5 | test('XML string', () => {
6 | const doc = $$.create('text ')
7 |
8 | expect($$.printTree(doc.node)).toBe($$.t`
9 | root att="val"
10 | # text
11 | `)
12 | })
13 |
14 | test('JS object', () => {
15 | const doc = $$.create({ root: { "@att": "val", "#": "text" }})
16 |
17 | expect($$.printTree(doc.node)).toBe($$.t`
18 | root att="val"
19 | # text
20 | `)
21 | })
22 |
23 | test('JSON string', () => {
24 | const doc = $$.create(JSON.stringify({ root: { "@att": "val", "#": "text" }}))
25 |
26 | expect($$.printTree(doc.node)).toBe($$.t`
27 | root att="val"
28 | # text
29 | `)
30 | })
31 |
32 | })
33 |
--------------------------------------------------------------------------------
/test/basic/remove.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('remove()', () => {
4 |
5 | test('remove element node', () => {
6 | const root = $$.create().ele('root')
7 | root.ele('node1').up().ele('node2').remove().ele('node3')
8 |
9 | expect($$.printTree(root.doc().node)).toBe($$.t`
10 | root
11 | node1
12 | node3
13 | `)
14 | })
15 |
16 | })
17 |
--------------------------------------------------------------------------------
/test/basic/sanitize.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('Sanitize input strings', () => {
4 |
5 | test('parser', () => {
6 | const doc = $$.create({ invalidCharReplacement: '' }, 'te\x08xt\x00root\x00>')
7 |
8 | expect(doc.end({ headless: true })).toBe($$.t`
9 | text
10 | `)
11 | })
12 |
13 | test('JS object', () => {
14 | const doc = $$.create({ invalidCharReplacement: '' }, { 'root\x00': 'te\x08xt' })
15 |
16 | expect(doc.end({ headless: true })).toBe($$.t`
17 | text
18 | `)
19 | })
20 |
21 | test('ele', () => {
22 | const doc = $$.create({ invalidCharReplacement: '' })
23 | .ele('root\x00').txt('te\x08xt')
24 | .doc()
25 |
26 | expect(doc.end({ headless: true })).toBe($$.t`
27 | text
28 | `)
29 | })
30 |
31 | test('ele et al.', () => {
32 | const obj = {
33 | ele: "simple \x00element",
34 | person: {
35 | name: "Jo\x00hn",
36 | '@a\x00ge': 35,
37 | '?\x001': 'pi val',
38 | '?\x002': 'pi\x00',
39 | '!\x00': 'Good guy',
40 | '$\x00': 'well formed!',
41 | address: {
42 | city: "Istan\x00bul",
43 | street: "End o\x00f long and winding road"
44 | },
45 | contact: {
46 | phone: ["555-\x001234", "555-\x001235"]
47 | },
48 | id: () => '4\x002',
49 | details: {
50 | '#text': 'class\x00ified'
51 | }
52 | }
53 | }
54 |
55 | expect($$.create({ version: "1.0", encoding: "UTF-8", standalone: true, invalidCharReplacement: '' })
56 | .ele('root').ele(obj).doc().toString({ format: "xml", prettyPrint: true })).toBe($$.t`
57 |
58 |
59 | simple element
60 |
61 | John
62 |
63 |
64 |
65 |
66 |
67 | Istanbul
68 | End of long and winding road
69 |
70 |
71 | 555-1234
72 | 555-1235
73 |
74 | 42
75 | classified
76 |
77 |
78 | `)
79 | })
80 |
81 | test('with replacement function - 1', () => {
82 | const doc = $$.create({ invalidCharReplacement: c => c === '\x00' ? '' : '_' })
83 | .ele('root\x00').txt('text\x08content')
84 | .doc()
85 |
86 | expect(doc.end({ headless: true })).toBe($$.t`
87 | text_content
88 | `)
89 | })
90 |
91 | test('with replacement function - 2', () => {
92 | const doc = $$.create({
93 | invalidCharReplacement: (c, i, str) => str.startsWith('root') ? '' : i === 0 ? '_' : ' '
94 | }).ele('root\x00').txt('\x00text\x08content')
95 | .doc()
96 |
97 | expect(doc.end({ headless: true })).toBe($$.t`
98 | _text content
99 | `)
100 | })
101 |
102 | })
103 |
--------------------------------------------------------------------------------
/test/basic/text.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('txt()', () => {
4 |
5 | test('basic', () => {
6 | const root = $$.create().ele('root')
7 | const node1 = root.ele('node1')
8 | node1.txt('node1 text').ele('node1-2')
9 | const node2 = root.ele('node2')
10 |
11 | expect($$.printTree(root.doc().node)).toBe($$.t`
12 | root
13 | node1
14 | # node1 text
15 | node1-2
16 | node2
17 | `)
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/basic/toString.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('toString()', () => {
4 |
5 | test('document', () => {
6 | const doc = $$.create().ele('root').doc()
7 | expect(doc.toString()).toBe(' ')
8 | })
9 |
10 | test('document type', () => {
11 | const doc = $$.create().dtd({ pubID: "pub", sysID: "sys" }).ele('root').doc()
12 | expect(doc.toString()).toBe(' ')
13 | })
14 |
15 | test('document fragment', () => {
16 | const frag = $$.fragment().ele('foo').ele('bar').up().up()
17 | expect(frag.toString()).toBe(' ')
18 | })
19 |
20 | test('element', () => {
21 | const root = $$.create().ele('root')
22 | expect(root.toString()).toBe(' ')
23 | })
24 |
25 | test('text', () => {
26 | const node = $$.create().ele('root').txt('content')
27 | expect(node.toString()).toBe('content ')
28 | })
29 |
30 | test('cdata', () => {
31 | const node = $$.create().ele('root').dat('content')
32 | expect(node.toString()).toBe(' ')
33 | })
34 |
35 | test('comment', () => {
36 | const node = $$.create().ele('root').com('content')
37 | expect(node.toString()).toBe(' ')
38 | })
39 |
40 | test('processing instruction', () => {
41 | const node = $$.create().ele('root').ins('target', 'content')
42 | expect(node.toString()).toBe(' ')
43 | })
44 |
45 | test('attribute', () => {
46 | const root = $$.create().ele('root').att("att", "val")
47 | expect(root.toString()).toBe(' ')
48 | })
49 |
50 | })
51 |
--------------------------------------------------------------------------------
/test/basic/traversal.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('traversal', () => {
4 |
5 | test('root()', () => {
6 | const root = $$.create().ele('root')
7 | .ele('node1').up()
8 | .ele('node2').up()
9 |
10 | expect(root.first().root()).toEqual(root)
11 | const emptyDoc = $$.create()
12 | expect(() => emptyDoc.root()).toThrow()
13 | })
14 |
15 | test('up()', () => {
16 | const root = $$.create().ele('root')
17 | .ele('node1').up()
18 | .ele('node2').up()
19 |
20 | expect(root.first().up()).toEqual(root)
21 | expect(() => root.first().up().up().up()).toThrow()
22 | })
23 |
24 | test('prev()', () => {
25 | const root = $$.create().ele('root')
26 | .ele('node1').up()
27 | .ele('node2').up()
28 |
29 | expect(root.last().prev().node.nodeName).toBe('node1')
30 | expect(() => root.first().prev()).toThrow()
31 | })
32 |
33 | test('next()', () => {
34 | const root = $$.create().ele('root')
35 | .ele('node1').up()
36 | .ele('node2').up()
37 |
38 | expect(root.first().next().node.nodeName).toBe('node2')
39 | expect(() => root.last().next()).toThrow()
40 | })
41 |
42 | test('first()', () => {
43 | const root = $$.create().ele('root')
44 | .ele('node1').up()
45 | .ele('node2').up()
46 |
47 | expect(root.first().node.nodeName).toBe('node1')
48 | expect(() => root.first().first()).toThrow()
49 | })
50 |
51 | test('last()', () => {
52 | const root = $$.create().ele('root')
53 | .ele('node1').up()
54 | .ele('node2').up()
55 |
56 | expect(root.last().node.nodeName).toBe('node2')
57 | expect(() => root.last().last()).toThrow()
58 | })
59 |
60 | })
61 |
--------------------------------------------------------------------------------
/test/basic/withOptions.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('withOptions()', () => {
4 |
5 | test('XML declaration', () => {
6 | expect(
7 | $$.create({ version: "1.0", encoding: "UTF-8", standalone: true })
8 | .ele('root').end()).toBe(
9 | ' '
10 | )
11 |
12 | expect(
13 | $$.create({ version: "1.0", encoding: "UTF-16", standalone: false })
14 | .ele('root').end()).toBe(
15 | ' '
16 | )
17 | })
18 |
19 | test('zero length converter strings', () => {
20 | expect(() => $$.create({ convert: { att: "" } })).toThrow()
21 | expect(() => $$.create({ convert: { ins: "" } })).toThrow()
22 | expect(() => $$.create({ convert: { text: "" } })).toThrow()
23 | expect(() => $$.create({ convert: { cdata: "" } })).toThrow()
24 | expect(() => $$.create({ convert: { comment: "" } })).toThrow()
25 | })
26 |
27 | })
28 |
--------------------------------------------------------------------------------
/test/callback/async-basic.test.out:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/callback/async.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { createWriteStream, readFile } from 'fs'
3 | import { resolve } from 'path'
4 |
5 | describe('Use callback API with fs async', () => {
6 |
7 | test('basic', (done) => {
8 | const xmlStr = ` `
9 |
10 | const filename = resolve(__dirname, 'async-basic.test.out')
11 | const outFile = createWriteStream(filename)
12 |
13 | const xmlStream = $$.createCB({
14 | 'data': (chunk: string) => outFile.write(chunk),
15 | 'end': () => outFile.end()
16 | })
17 |
18 | outFile.on('close', () => {
19 | readFile(filename, 'utf8', (err, result) => {
20 | expect(result).toBe(xmlStr)
21 | done()
22 | })
23 | })
24 |
25 | xmlStream.ele("root")
26 | .ele("foo").up()
27 | .ele("bar").att("fizz", "buzz").up()
28 | .end()
29 | })
30 |
31 | test('many', (done) => {
32 | const count = 1000
33 | let xmlStr = ""
34 | for (let i = 1; i < count; i++) {
35 | xmlStr += " "
36 | }
37 | xmlStr += " "
38 |
39 | const filename = resolve(__dirname, 'async-many.test.out')
40 | const outFile = createWriteStream(filename)
41 |
42 | const xmlStream = $$.createCB({
43 | 'data': (chunk: string) => outFile.write(chunk),
44 | 'end': () => outFile.end()
45 | })
46 |
47 | outFile.on('close', () => {
48 | readFile(filename, 'utf8', (err, result) => {
49 | expect(result).toBe(xmlStr)
50 | done()
51 | })
52 | })
53 |
54 | xmlStream.ele("root")
55 | for (let i = 1; i < count; i++) {
56 | xmlStream.ele("node" + i.toString()).att("att" + i.toString(), "val" + i.toString()).up()
57 | }
58 | xmlStream.end()
59 | })
60 |
61 | })
62 |
--------------------------------------------------------------------------------
/test/callback/dec.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('dec()', () => {
4 |
5 | test('dec() with default version', (done) => {
6 | const xmlStream = $$.createCB({ prettyPrint: true })
7 |
8 | xmlStream.dec().ele('root').end()
9 |
10 | $$.expectCBResult(xmlStream, $$.t`
11 |
12 | `, done)
13 | })
14 |
15 | test('dec() with version', (done) => {
16 | const xmlStream = $$.createCB({ prettyPrint: true })
17 |
18 | xmlStream.dec({ version: "1.0" }).ele('root').end()
19 |
20 | $$.expectCBResult(xmlStream, $$.t`
21 |
22 | `, done)
23 | })
24 |
25 | test('dec() with encoding', (done) => {
26 | const xmlStream = $$.createCB({ prettyPrint: true })
27 |
28 | xmlStream.dec({ encoding: "US-ASCII" }).ele('root').end()
29 |
30 | $$.expectCBResult(xmlStream, $$.t`
31 |
32 | `, done)
33 | })
34 |
35 | test('dec() with standalone true', (done) => {
36 | const xmlStream = $$.createCB({ prettyPrint: true })
37 |
38 | xmlStream.dec({ standalone: true }).ele('root').end()
39 |
40 | $$.expectCBResult(xmlStream, $$.t`
41 |
42 | `, done)
43 | })
44 |
45 | test('dec() with standalone false', (done) => {
46 | const xmlStream = $$.createCB({ prettyPrint: true })
47 |
48 | xmlStream.dec({ standalone: false }).ele('root').end()
49 |
50 | $$.expectCBResult(xmlStream, $$.t`
51 |
52 | `, done)
53 | })
54 |
55 | test('dec() with all settings', (done) => {
56 | const xmlStream = $$.createCB({ prettyPrint: true })
57 |
58 | xmlStream.dec({ version: "1.0", encoding: "US-ASCII", standalone: false }).ele('root').end()
59 |
60 | $$.expectCBResult(xmlStream, $$.t`
61 |
62 | `, done)
63 | })
64 |
65 | })
--------------------------------------------------------------------------------
/test/callback/dtd.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('dtd()', () => {
4 |
5 | test('doctype with both public and system identifier', (done) => {
6 | const xmlStream = $$.createCB({ prettyPrint: true })
7 |
8 | xmlStream.dec({ version: "1.0" })
9 | .dtd({ name: 'root', pubID: "pub", sysID: "sys" })
10 | .ele('ns', 'root').end()
11 |
12 | $$.expectCBResult(xmlStream, $$.t`
13 |
14 |
15 | `, done)
16 | })
17 |
18 | test('doctype with public identifier', (done) => {
19 | const xmlStream = $$.createCB({ prettyPrint: true })
20 |
21 | xmlStream.dec({ version: "1.0" })
22 | .dtd({ name: 'root', pubID: "pub" })
23 | .ele('ns', 'root').end()
24 |
25 | $$.expectCBResult(xmlStream, $$.t`
26 |
27 |
28 | `, done)
29 | })
30 |
31 | test('doctype with system identifier', (done) => {
32 | const xmlStream = $$.createCB({ prettyPrint: true })
33 |
34 | xmlStream.dec({ version: "1.0" })
35 | .dtd({ name: 'root', sysID: "sys" })
36 | .ele('ns', 'root').end()
37 |
38 | $$.expectCBResult(xmlStream, $$.t`
39 |
40 |
41 | `, done)
42 | })
43 |
44 | test('doctype without identifiers', (done) => {
45 | const xmlStream = $$.createCB({ prettyPrint: true })
46 |
47 | xmlStream.dec({ version: "1.0" })
48 | .dtd({ name: 'root' })
49 | .ele('ns', 'root').end()
50 |
51 | $$.expectCBResult(xmlStream, $$.t`
52 |
53 |
54 | `, done)
55 | })
56 |
57 | })
--------------------------------------------------------------------------------
/test/callback/fragment.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('basic XMLStream tests', () => {
4 |
5 | test('empty document', (done) => {
6 | const xmlStream = $$.fragmentCB()
7 |
8 | xmlStream.end()
9 |
10 | $$.expectCBResult(xmlStream, ``, done)
11 | })
12 |
13 | test('ele', (done) => {
14 | const xmlStream = $$.fragmentCB()
15 |
16 | xmlStream.ele("root").end()
17 |
18 | $$.expectCBResult(xmlStream, ` `, done)
19 | })
20 |
21 | test('ele with children', (done) => {
22 | const xmlStream = $$.fragmentCB()
23 |
24 | xmlStream.ele("root")
25 | .ele("foo")
26 | .ele("bar").up()
27 | .ele("baz").up()
28 | .end()
29 |
30 | $$.expectCBResult(xmlStream, ` `, done)
31 | })
32 |
33 | test('multiple elements at root level', (done) => {
34 | const xmlStream = $$.fragmentCB()
35 |
36 | xmlStream.ele("node").up()
37 | .ele("node")
38 | .ele("bar").up()
39 | .ele("baz").up()
40 | .up()
41 | .end()
42 |
43 | $$.expectCBResult(xmlStream, ` `, done)
44 | })
45 |
46 | test('dec', (done) => {
47 | const xmlStream = $$.fragmentCB()
48 |
49 | $$.expectCBError(xmlStream, () => xmlStream.dec({ version: "1.0", encoding: "UTF-8", standalone: true }), done)
50 | })
51 |
52 | test('dtd', (done) => {
53 | const xmlStream = $$.fragmentCB()
54 |
55 | $$.expectCBError(xmlStream, () => xmlStream.dtd({ name: "root", pubID: "pub", sysID: "sys" }), done)
56 | })
57 |
58 | test('txt', (done) => {
59 | const xmlStream = $$.fragmentCB()
60 |
61 | xmlStream.ele("root")
62 | .txt("text")
63 | .txt("")
64 | .end()
65 |
66 | $$.expectCBResult(xmlStream, `text `, done)
67 | })
68 |
69 | test('txt at root level', (done) => {
70 | const xmlStream = $$.fragmentCB()
71 |
72 | xmlStream.txt("text")
73 | .end()
74 |
75 | $$.expectCBResult(xmlStream, `text`, done)
76 | })
77 |
78 | test('com', (done) => {
79 | const xmlStream = $$.fragmentCB()
80 |
81 | xmlStream.ele("root")
82 | .com("text")
83 | .end()
84 |
85 | $$.expectCBResult(xmlStream, ` `, done)
86 | })
87 |
88 | test('dat', (done) => {
89 | const xmlStream = $$.fragmentCB()
90 |
91 | xmlStream.ele("root")
92 | .dat("text")
93 | .end()
94 |
95 | $$.expectCBResult(xmlStream, ` `, done)
96 | })
97 |
98 | test('ins', (done) => {
99 | const xmlStream = $$.fragmentCB()
100 |
101 | xmlStream.ele("root")
102 | .ins("target", "value")
103 | .end()
104 |
105 | $$.expectCBResult(xmlStream, ` `, done)
106 | })
107 |
108 | })
109 |
--------------------------------------------------------------------------------
/test/callback/object.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('object', () => {
4 |
5 | test('from JS object with decorators', (done) => {
6 | const obj = {
7 | root: {
8 | ele: "simple element",
9 | person: {
10 | name: "John",
11 | '@age': 35,
12 | '?1': 'pi val',
13 | '?2': 'pi',
14 | '!': 'Good guy',
15 | '$': 'well formed!',
16 | address: {
17 | '?': 'pi',
18 | city: "Istanbul",
19 | street: "End of long and winding road"
20 | },
21 | contact: {
22 | phone: ["555-1234", "555-1235"]
23 | },
24 | id: () => 42,
25 | details: {
26 | '#': 'classified'
27 | }
28 | }
29 | }
30 | }
31 |
32 | const xmlStream = $$.createCB({ prettyPrint: true })
33 |
34 | xmlStream.ele(obj).end()
35 |
36 | $$.expectCBResult(xmlStream, $$.t`
37 |
38 |
39 | simple element
40 |
41 |
42 |
43 | John
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Istanbul
53 |
54 |
55 | End of long and winding road
56 |
57 |
58 |
59 |
60 | 555-1234
61 |
62 |
63 | 555-1235
64 |
65 |
66 |
67 | 42
68 |
69 |
70 | classified
71 |
72 |
73 |
74 | `, done)
75 | })
76 |
77 | test('namespace', (done) => {
78 | const obj = {
79 | root: {
80 | "@xmlns": "ns"
81 | }
82 | }
83 |
84 | const xmlStream = $$.createCB({ prettyPrint: true })
85 |
86 | xmlStream.ele(obj).end()
87 |
88 | $$.expectCBResult(xmlStream, $$.t`
89 |
90 | `, done)
91 | })
92 |
93 | test('element with namespace', (done) => {
94 | const obj = {
95 | "root@ns": {}
96 | }
97 |
98 | const xmlStream = $$.createCB({ prettyPrint: true })
99 |
100 | xmlStream.ele(obj).end()
101 |
102 | $$.expectCBResult(xmlStream, $$.t`
103 |
104 | `, done)
105 | })
106 |
107 | test('attribute with namespace', (done) => {
108 | const obj = {
109 | root: {
110 | "@isbn@book": "111"
111 | }
112 | }
113 |
114 | const xmlStream = $$.createCB({ prettyPrint: true })
115 |
116 | xmlStream.ele(obj).end()
117 |
118 | $$.expectCBResult(xmlStream, $$.t`
119 |
120 | `, done)
121 | })
122 |
123 | })
124 |
--------------------------------------------------------------------------------
/test/callback/parse.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('parse()', () => {
4 |
5 | test('XML string', (done) => {
6 | const str = 'text '
7 |
8 | const xmlStream = $$.createCB({ prettyPrint: true })
9 |
10 | xmlStream.ele(str).end()
11 |
12 | $$.expectCBResult(xmlStream, $$.t`
13 |
14 | text
15 |
16 | `, done)
17 | })
18 |
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/dom/sanitizeInput.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { sanitizeInput } from '../../src/builder/dom'
3 |
4 | describe('sanitizeInput', () => {
5 |
6 | test('replacement char', () => {
7 | expect(sanitizeInput(undefined, '')).toBe(undefined)
8 | expect(sanitizeInput(null, '')).toBe(null)
9 | expect(sanitizeInput('hello\x00')).toBe('hello\x00')
10 | expect(sanitizeInput('\x09\x0A\x0D\x20\uE000', '')).toBe('\x09\x0A\x0D\x20\uE000')
11 | // surrogate pair
12 | expect(sanitizeInput('😀', '')).toBe('😀')
13 | expect(sanitizeInput('\uD83D\uDE00', '')).toBe('😀')
14 | // lone surrogate
15 | expect(sanitizeInput('\uD83D\uFFFF', '')).toBe('')
16 | // invalid surrogate pair
17 | expect(sanitizeInput('😀', '')).toBe('😀')
18 | })
19 |
20 | test('replacement function', () => {
21 | expect(sanitizeInput(undefined, () => '')).toBe(undefined)
22 | expect(sanitizeInput(null, () => '')).toBe(null)
23 | expect(sanitizeInput('hello\x00')).toBe('hello\x00')
24 | expect(sanitizeInput('\x09\x0A\x0D\x20\uE000', () => '')).toBe('\x09\x0A\x0D\x20\uE000')
25 | // surrogate pair
26 | expect(sanitizeInput('😀', () => '')).toBe('😀')
27 | expect(sanitizeInput('\uD83D\uDE00', () => '')).toBe('😀')
28 | // lone surrogate
29 | expect(sanitizeInput('\uD83D\uFFFF', () => '')).toBe('')
30 | // invalid surrogate pair
31 | expect(sanitizeInput('😀', () => '')).toBe('😀')
32 | })
33 |
34 | })
35 |
--------------------------------------------------------------------------------
/test/issues/issue-001.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('Replicate issue', () => {
4 |
5 | // https://github.com/oozcitak/xmlbuilder2/issues/1
6 | test('#1 - xmlns attribute added to the root element is shown on its child elements', () => {
7 | const doc = $$.create()
8 | .ele('SomeRootTag')
9 | .att({ xmlns: 'http://example.com', x: 0 })
10 | .ele('foo')
11 | .att({ a: 'A1', x: 1 })
12 | .doc()
13 | const root = doc.root()
14 | const foo = root.first()
15 | expect(foo.toString()).toBe(' ')
16 | expect(root.toString()).toBe(' ')
17 | expect(doc.end({ headless: true })).toBe($$.t`
18 |
19 | `)
20 | })
21 |
22 | })
23 |
--------------------------------------------------------------------------------
/test/issues/issue-002.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/2
5 | test(`#2 - Reconsider allowing XML file creation in chunks`, (done) => {
6 | const xmlStream = $$.createCB({ prettyPrint: true })
7 |
8 | const item1 = $$.create({
9 | item: {
10 | sku: '001',
11 | name: 'Product name 1',
12 | }
13 | });
14 | const item2 = $$.create({
15 | item: {
16 | sku: '002',
17 | name: 'Product name 2',
18 | }
19 | });
20 |
21 | xmlStream.dec().ele('rss').import(item1).import(item2).end()
22 |
23 | $$.expectCBResult(xmlStream, $$.t`
24 |
25 |
26 | -
27 |
28 | 001
29 |
30 |
31 | Product name 1
32 |
33 |
34 | -
35 |
36 | 002
37 |
38 |
39 | Product name 2
40 |
41 |
42 |
43 | `, done)
44 | })
45 |
46 | })
47 |
--------------------------------------------------------------------------------
/test/issues/issue-006.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('Replicate issue', () => {
4 |
5 | // https://github.com/oozcitak/xmlbuilder2/issues/6
6 | test('#6 - When using namespace, empty XMLNs shows up in various child node elements', () => {
7 | const doc = $$.create()
8 | .ele("http://example.com", "parent")
9 | .ele("child").doc()
10 |
11 | expect(doc.end({ headless: true })).toBe($$.t`
12 |
13 | `)
14 | })
15 |
16 | })
17 |
--------------------------------------------------------------------------------
/test/issues/issue-008.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { useNamespaces } from "xpath"
3 |
4 | describe('Replicate issue', () => {
5 |
6 | // https://github.com/oozcitak/xmlbuilder2/issues/8
7 | test('#8 - xpath on native object does not work', () => {
8 | const doc = $$.create({ version: "1.0", encoding: "utf-8" })
9 | .ele("myns:root", { "xmlns:myns": "http://www.google.com/myns/" })
10 | .ele("myns:child1")
11 | .txt(`child1_value`)
12 | .up()
13 | .ele("myns:child1")
14 | .txt(`child1_value`)
15 | .up()
16 | .doc()
17 |
18 | const select = useNamespaces({
19 | myns: "http://www.google.com/myns/"
20 | })
21 |
22 | const result = select("//myns:child1", doc.node as any) as any
23 | expect(result.length).toBe(2)
24 | expect(result[0].tagName).toBe("myns:child1")
25 | expect(result[1].tagName).toBe("myns:child1")
26 | })
27 |
28 | test('#8 - correct usage', () => {
29 | const doc = $$.create({ version: "1.0", encoding: "utf-8" })
30 | .ele("http://www.google.com/myns/", "myns:root")
31 | .ele("http://www.google.com/myns/", "myns:child1")
32 | .txt(`child1_value`)
33 | .up()
34 | .ele("http://www.google.com/myns/", "myns:child1")
35 | .txt(`child1_value`)
36 | .up()
37 | .doc()
38 |
39 | const select = useNamespaces({
40 | myns: "http://www.google.com/myns/"
41 | })
42 |
43 | const result = select("//myns:child1", doc.node as any) as any
44 | expect(result.length).toBe(2)
45 | expect(result[0].tagName).toBe("myns:child1")
46 | expect(result[1].tagName).toBe("myns:child1")
47 | expect(doc.end({ prettyPrint: true })).toBe($$.t`
48 |
49 |
50 | child1_value
51 | child1_value
52 |
53 | `)
54 | })
55 |
56 | test('#8 - same with parser', () => {
57 | const doc = $$.create({ version: "1.0", encoding: "utf-8" })
58 | .ele("myns:root", { "xmlns:myns": "http://www.google.com/myns/" })
59 | .ele("myns:child1")
60 | .txt(`child1_value`)
61 | .up()
62 | .ele("myns:child1")
63 | .txt(`child1_value`)
64 | .up()
65 |
66 | const doc2 = $$.create(doc.toString());
67 |
68 | const select = useNamespaces({
69 | myns: "http://www.google.com/myns/"
70 | })
71 | select("//myns:child1", doc2.node as any);
72 |
73 | const result = select("//myns:child1", doc2.node as any) as any
74 | expect(result.length).toBe(2)
75 | expect(result[0].tagName).toBe("myns:child1")
76 | expect(result[1].tagName).toBe("myns:child1")
77 | })
78 | })
79 |
--------------------------------------------------------------------------------
/test/issues/issue-013.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('Replicate issue', () => {
4 |
5 | // https://github.com/oozcitak/xmlbuilder2/issues/13
6 | test('#13 - Parsing JS object with default namespace declaration attribute throws error', () => {
7 | const str = $$.convert(
8 | { feed: { "@xmlns": "http://www.w3.org/2005/Atom" } },
9 | { headless: true, wellFormed: true }
10 | )
11 |
12 | expect(str).toBe(` `)
13 | })
14 |
15 | test('#13 - with prefix', () => {
16 | const str = $$.convert(
17 | { "p:feed": { "@xmlns:p": "http://www.w3.org/2005/Atom" } },
18 | { headless: true, wellFormed: true }
19 | )
20 |
21 | expect(str).toBe(` `)
22 | })
23 |
24 | })
25 |
--------------------------------------------------------------------------------
/test/issues/issue-015.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('Replicate issue', () => {
4 |
5 | // https://github.com/oozcitak/xmlbuilder2/issues/15
6 | test('#15 - Fix decoding of entities on conversion from XML to object', () => {
7 | const originalXML = `<p>Hello</p> `
8 | const objectXML = $$.convert(originalXML, { format: "object" })
9 | const recreatedXML = $$.convert(objectXML, { format: "xml" })
10 |
11 | expect(recreatedXML).toBe(originalXML)
12 | })
13 |
14 | })
15 |
--------------------------------------------------------------------------------
/test/issues/issue-016.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/16
5 | test("#16 - Named entities produce invalid XML", () => {
6 | expect(
7 | $$.convert(
8 | { example: "<p>Hello World</p>" },
9 | { format: "xml" }
10 | )
11 | ).toBe(
12 | '<p>Hello World</p> '
13 | );
14 | expect(
15 | $$.convert(
16 | { example: "¬anentity<" },
17 | { format: "xml" }
18 | )
19 | ).toBe('¬anentity< ')
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/test/issues/issue-018.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/18
5 | test("#18 - Bring back inherit namespaces", () => {
6 | const doc = $$.create({ version: '1.0', encoding: 'UTF-8' })
7 | .ele('Invoice', { xmlns: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2', 'xmlns:cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', 'xmlns:cbc': "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" })
8 |
9 | let frag = $$.fragment()
10 | frag.ele('cbc:StreetName').txt('Karl Johans gate 45')
11 | frag.ele('cbc:CityName').txt('Oslo')
12 | frag.ele('cbc:PostalZone').txt('0162')
13 | frag.ele('cac:Country')
14 | .ele('cbc:IdentificationCode', { listID: "ISO3166-1:Alpha2" })
15 | .txt('NO')
16 |
17 | doc.ele('cac:Address').import(frag)
18 | expect(doc.end({ prettyPrint: true })).toBe($$.t`
19 |
20 |
21 |
22 | Karl Johans gate 45
23 | Oslo
24 | 0162
25 |
26 | NO
27 |
28 |
29 |
30 | `)
31 | })
32 | })
33 |
--------------------------------------------------------------------------------
/test/issues/issue-020.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/20
5 | test("#20 - Setting xmlns causes problem on children", () => {
6 | const node = $$.create({ root: { child: 'child text' } })
7 | const node2 = $$.create().ele('root').ele('child').txt('child text').up().up();
8 |
9 | expect(node.end({ prettyPrint: true, headless: true })).toBe($$.t`
10 |
11 | child text
12 |
13 | `)
14 | expect(node.root().att('xmlns', 'anything').end({ prettyPrint: true, headless: true })).toBe($$.t`
15 |
16 | child text
17 |
18 | `)
19 |
20 | expect(node2.end({ prettyPrint: true, headless: true })).toBe($$.t`
21 |
22 | child text
23 |
24 | `)
25 | expect(node2.root().att('xmlns', 'anything').end({ prettyPrint: true, headless: true })).toBe($$.t`
26 |
27 | child text
28 |
29 | `)
30 | })
31 |
32 | })
33 |
--------------------------------------------------------------------------------
/test/issues/issue-021.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/21
5 | test("#21 - Number 0 is omitted when converting object to xml", () => {
6 | expect($$.create().ele({ value: 0 }).end({ headless: true })).toBe('0 ')
7 | })
8 |
9 | })
10 |
--------------------------------------------------------------------------------
/test/issues/issue-024.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/24
5 | test("#24 - \r encoding in element txt", () => {
6 | const root = $$.create().ele('parent', {
7 | text: 'Hello \r\n'
8 | }).ele('child').txt('Line 1\r\nLine 2\r\nLine 3')
9 |
10 | expect(root.end({ headless: true, prettyPrint: true, newline: '\r\n' })).toBe(
11 | '\r\n' +
12 | ' Line 1\r\n' +
13 | 'Line 2\r\n' +
14 | 'Line 3 \r\n' +
15 | ' '
16 | )
17 | })
18 |
19 | })
20 |
--------------------------------------------------------------------------------
/test/issues/issue-025.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 | import { XMLBuilder } from "../../src/interfaces";
3 |
4 | describe("Replicate issue", () => {
5 | // https://github.com/oozcitak/xmlbuilder2/issues/25
6 | test("#25 - Custom converter", () => {
7 | const obj = {
8 | 'root': {
9 | '-ns:ns1:some/uri': {
10 | 'node1': 'Some text',
11 | 'node2': 1234
12 | }
13 | }
14 | }
15 |
16 | let prefix: string | undefined
17 | let ns: string | undefined
18 | const doc = $$.create({
19 | parser: {
20 | element: function(this: any, parent: XMLBuilder, namespace: string | null | undefined, name: string): XMLBuilder | undefined {
21 | if (name.startsWith('-ns:')) {
22 | let [elePrefix, eleNS] = name.substring(4).split(':')
23 | if (eleNS === undefined) {
24 | prefix = undefined
25 | ns = undefined
26 | return undefined
27 | } else {
28 | prefix = elePrefix
29 | ns = eleNS
30 | return parent.att('xmlns:' + prefix, eleNS)
31 | }
32 | } else {
33 | return prefix ? parent.ele(prefix + ':' + name) : parent.ele(name)
34 | }
35 | }
36 | }
37 | }, obj);
38 |
39 | expect(doc.end({ headless: true, prettyPrint: true })).toBe($$.t`
40 |
41 | Some text
42 | 1234
43 |
44 | `)
45 |
46 | expect((doc.root().first().node as any).namespaceURI).toBe('some/uri')
47 | expect((doc.root().last().node as any).namespaceURI).toBe('some/uri')
48 | })
49 |
50 | })
51 |
--------------------------------------------------------------------------------
/test/issues/issue-029.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/29
5 | test("#29 - Attribute is a node", () => {
6 | const input = $$.t`
7 |
8 |
9 | %1$s
10 | until holiday
11 | %1$s
12 | anything
13 |
14 | `
15 |
16 | // test with default converter
17 | expect($$.convert(input, { format: 'object' })).toEqual(
18 | {
19 | resources: {
20 | string: {
21 | '@name': 'countdown',
22 | '#': [
23 | {
24 | 'xliff:g': {
25 | '@id': 'count',
26 | '@example': '2 days',
27 | '#': '%1$s'
28 | }
29 | },
30 | { '#': '\n until holiday\n ' },
31 | {
32 | 'xliff:g': {
33 | '@id': 'time',
34 | '@example': '5 days',
35 | '#': '%1$s'
36 | }
37 | },
38 | { '#': '\n anything\n ' },
39 | ]
40 | }
41 | }
42 | }
43 | )
44 |
45 | // test with custom converter
46 | const obj = $$.convert({ encoding: 'UTF-8', convert: { text: 'value' } }, input, { format: 'object' })
47 |
48 | expect(obj).toEqual(
49 | {
50 | resources: {
51 | string: {
52 | '@name': 'countdown',
53 | value: [
54 | {
55 | 'xliff:g': {
56 | '@id': 'count',
57 | '@example': '2 days',
58 | value: '%1$s'
59 | }
60 | },
61 | { value: '\n until holiday\n ' },
62 | {
63 | 'xliff:g': {
64 | '@id': 'time',
65 | '@example': '5 days',
66 | value: '%1$s'
67 | }
68 | },
69 | { value: '\n anything\n ' },
70 | ]
71 | }
72 | }
73 | }
74 | )
75 | })
76 |
77 | })
78 |
--------------------------------------------------------------------------------
/test/issues/issue-030.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/30
5 | test("#30 - Conversion from XML to JSON array inconsistency", () => {
6 | const input2 = $$.t`
7 |
8 |
9 | X
10 | 123
11 |
12 |
13 | Y
14 | 321
15 |
16 | `
17 |
18 | const obj2 = $$.convert(input2, { format: 'object', verbose: true })
19 | expect(obj2).toEqual(
20 | {
21 | "data": [
22 | {
23 | "row": [
24 | {
25 | "@id": "0",
26 | "TYPE": [ "X" ],
27 | "ID": [ "123" ]
28 | },
29 | {
30 | "@id": "1",
31 | "TYPE": [ "Y" ],
32 | "ID": [ "321" ]
33 | }
34 | ]
35 | }
36 | ]
37 | })
38 | expect($$.create(obj2).end({ headless: true, prettyPrint: true })).toBe(input2)
39 |
40 | const input1 = $$.t`
41 |
42 |
43 | X
44 | 123
45 |
46 | `
47 | const obj1 = $$.convert(input1, { format: 'object', verbose: true })
48 | expect(obj1).toEqual(
49 | {
50 | "data": [
51 | {
52 | "row": [
53 | {
54 | "@id": "0",
55 | "TYPE": [ "X" ],
56 | "ID": [ "123" ]
57 | }
58 | ]
59 | }
60 | ]
61 | })
62 | expect($$.create(obj1).end({ headless: true, prettyPrint: true })).toBe(input1)
63 | })
64 |
65 | })
66 |
--------------------------------------------------------------------------------
/test/issues/issue-031.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/31
5 | test("#31 - `convert` method don't group multiple attributes", () => {
6 | const input = $$.t`
7 |
8 | Main title
9 |
10 | %1$s
11 | until holiday
12 | %1$s
13 | anything
14 | %1$s
15 |
16 |
17 | - One
18 | - two
19 |
20 |
21 | - Three
22 | - Four
23 |
24 | `
25 |
26 | const obj = $$.convert({ convert: { text: 'value' } }, input, { format: 'object', group: true })
27 | expect(obj).toEqual(
28 | {
29 | "resources": {
30 | "string": [
31 | {
32 | "@": {
33 | "id": "app_name",
34 | "name": "app_name",
35 | },
36 | "value": "Main title",
37 | },
38 | {
39 | "@": {
40 | "id": "countdown",
41 | "name": "countdown",
42 | },
43 | "value": [
44 | {
45 | "xliff:g": {
46 | "@": {
47 | "example": "2 days",
48 | "id": "count",
49 | },
50 | "value": "%1$s",
51 | },
52 | },
53 | {
54 | "value": "\n until holiday\n ",
55 | },
56 | {
57 | "xliff:g": {
58 | "@": {
59 | "example": "5 days",
60 | "id": "time",
61 | },
62 | "value": "%1$s",
63 | },
64 | },
65 | {
66 | "value": "\n anything\n ",
67 | },
68 | {
69 | "xliff:g": {
70 | "@": {
71 | "example": "1 days",
72 | "id": "qwe",
73 | },
74 | "value": "%1$s",
75 | },
76 | },
77 | ],
78 | },
79 | ],
80 | "string-array": [
81 | {
82 | "@": {
83 | "id": "numbers",
84 | "name": "numbers",
85 | },
86 | "item": [
87 | "One",
88 | "two",
89 | ],
90 | },
91 | {
92 | "@": {
93 | "id": "numbers2",
94 | "name": "numbers2",
95 | },
96 | "item": [
97 | "Three",
98 | "Four",
99 | ],
100 | },
101 | ],
102 | },
103 | })
104 |
105 | })
106 |
107 | })
108 |
--------------------------------------------------------------------------------
/test/issues/issue-037.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/37
5 | test("#37 - namespace error with AEM content fragment", () => {
6 | const cf = {
7 | 'jcr:root': {
8 | '@xmlns:jcr': 'http://www.jcp.org/jcr/1.0',
9 | 'jcr:content' :{
10 | data: {
11 | master: {
12 | '@id': '1234'
13 | }
14 | }
15 | }
16 | }
17 | }
18 | const doc = $$.create(cf);
19 | const xml = doc.end({ headless: true, prettyPrint: true });
20 | expect(xml).toEqual($$.t`
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | `)
29 |
30 | })
31 |
32 | const xml = ` `
33 | const doc = $$.create(xml)
34 | const obj = doc.end( { format: "object" })
35 | expect(obj).toEqual({
36 | root: {
37 | '@xmlns:soap12': 'http://www.w3.org/2003/05/soap-envelope',
38 | 'soap12:node': { }
39 | }
40 | })
41 | const xmlr = $$.create(obj).end({ headless: true })
42 | expect(xmlr).toBe(xml)
43 |
44 | })
45 |
--------------------------------------------------------------------------------
/test/issues/issue-043.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { select } from "xpath"
3 |
4 | describe('Replicate issue', () => {
5 |
6 | // https://github.com/oozcitak/xmlbuilder2/issues/43
7 | test('#43 - Add an Element (from XPath query) to xmlbuilder2 object', () => {
8 | const doc1 = $$.create()
9 | .ele("records")
10 | .ele("record", { id: 1 }).up()
11 | .ele("record", { id: 2 }).up()
12 | .doc()
13 |
14 | const doc2 = $$.create()
15 | .ele("results")
16 | .doc()
17 |
18 | const result = select("//record", doc1.node as any)
19 | if (result && result.length && result.length !== 0) {
20 | const recordNode = $$.builder(result[0] as any)
21 | doc2.root().import(recordNode)
22 | }
23 | expect(doc2.end({ prettyPrint: true })).toBe($$.t`
24 |
25 |
26 |
27 |
28 | `)
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/test/issues/issue-044.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { select } from "xpath"
3 |
4 | describe('Replicate issue', () => {
5 |
6 | // https://github.com/oozcitak/xmlbuilder2/issues/44
7 | test('#44 - Converting XML to JSON does not escape invalid string characters', () => {
8 | const jsonStr = $$.convert('b\nc ', { format: 'json' })
9 | expect(jsonStr).toBe(`{"a":"b\\nc"}`)
10 |
11 | const invalidChars = Array.from(Array(0x20), (_, i) => {
12 | return String.fromCharCode(i);
13 | }).concat('"', '\\')
14 |
15 | const xml = $$.convert(
16 | `${invalidChars.map((c) => `_${c}_ `).join('\n')} `
17 | )
18 | const json = $$.convert(xml, { format: 'json' })
19 | expect(() => JSON.parse(json)).not.toThrow()
20 |
21 | const obj = $$.convert(xml, { format: 'object' })
22 | expect(JSON.stringify(obj)).toBe(json)
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/test/issues/issue-045.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 | import { XMLBuilder } from "../../src/interfaces";
3 |
4 | describe("Replicate issue", () => {
5 | // https://github.com/oozcitak/xmlbuilder2/issues/45
6 | test("#45 - How to convert an Json Array into Xml Array like this", () => {
7 | const obj = {
8 | 'root': {
9 | 'items': [
10 | { '@id': 1 },
11 | { '@id': 2 },
12 | { '@id': 3 }
13 | ]
14 | }
15 | }
16 |
17 | const elementParser = function (parent: XMLBuilder, namespace: any, name: string) {
18 | // check if we have a plural name
19 | if (name.endsWith('s')) {
20 | // check if we have a parent node with the same name
21 | // otherwise create one
22 | let itemsNode = parent.find(n => n.node.nodeName === name)
23 | if (itemsNode === undefined) {
24 | itemsNode = parent.ele(name)
25 | }
26 |
27 | let childName = name.slice(0, -1)
28 | return itemsNode.ele(childName)
29 | } else {
30 | return parent.ele(name)
31 | }
32 | }
33 |
34 | const doc = $$.create({ parser: { element: elementParser } }, obj)
35 |
36 | expect(doc.end({ headless: true, prettyPrint: true })).toBe($$.t`
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | `)
45 | })
46 |
47 | })
48 |
--------------------------------------------------------------------------------
/test/issues/issue-046.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 | import { XMLBuilder } from "../../src/interfaces";
3 |
4 | describe("Replicate issue", () => {
5 | // https://github.com/oozcitak/xmlbuilder2/issues/46
6 | test("#46 - Renaming elements through custom parser throws closing tag error", () => {
7 | const xml = $$.t`
8 |
9 |
10 |
11 |
12 | `
13 |
14 | const obj = $$.convert({
15 | parser: {
16 | element: (parent, _, name) => parent.ele("_" + name)
17 | },
18 | }, xml, {
19 | format: 'object'
20 | })
21 |
22 | expect(obj).toEqual(
23 | {
24 | "_root": {
25 | "_node1": {},
26 | "_node2": {}
27 | }
28 | })
29 | })
30 |
31 | })
32 |
--------------------------------------------------------------------------------
/test/issues/issue-048.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/48
5 | test("#48 - invalidCharReplacement does not work in a convert scenario", () => {
6 | const xml = `
7 |
8 |
9 |
10 |
11 | `
12 |
13 | const obj = $$.convert({ invalidCharReplacement: '' }, xml, { format: 'object' })
14 |
15 | expect(obj).toEqual(
16 | {
17 | "root": {
18 | "node1": {},
19 | "node2": {}
20 | }
21 | })
22 | })
23 |
24 | })
25 |
--------------------------------------------------------------------------------
/test/issues/issue-051.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/51
5 | test("#51 - NamespaceError: The operation is not allowed by Namespaces in XML. [XMLNS] Qualified name includes a prefix but the namespace is null.", () => {
6 | const root = $$.create({ version: '1.0', encoding: 'utf-8' })
7 | .ele('archive', {
8 | version: '4.0',
9 | 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
10 | 'xsi:schemaLocation': 'http://xml.datev.de/bedi/tps/document/v04.0 document_v040.xsd',
11 | xmlns: 'http://xml.datev.de/bedi/tps/document/v04.0'
12 | })
13 | const xml = root.end({ headless: true, prettyPrint: true });
14 |
15 | expect(xml).toBe($$.t`
16 |
17 | `)
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/issues/issue-056.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/56
5 | test(`#56 - Throws TypeError "Cannot read property 'length' of null" when specifying null txt`, () => {
6 | const xml = $$.create().ele('test').txt(null as any).end({ headless: true })
7 |
8 | expect(xml).toBe(' ')
9 | })
10 |
11 | })
12 |
--------------------------------------------------------------------------------
/test/issues/issue-060.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/60
5 | test(`#60 - How to add stylesheet for sitemap?`, () => {
6 | const doc = $$.create({ version: '1.0', encoding: 'UTF-8' })
7 | .ins('xml-stylesheet', 'type="text/xsl" href="//example.com/sitemap.xsl"')
8 | .ele('sitemapindex', { xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9' })
9 | .ele('sitemap')
10 | .ele('loc').txt('https://example.com/sitemap-posts.xml').up()
11 | .ele('lastmod').txt('2020-10-06T14:04:09.000Z').up()
12 | .up()
13 | .up()
14 | .doc()
15 |
16 | expect(doc.end({prettyPrint: true })).toBe($$.t`
17 |
18 |
19 |
20 |
21 | https://example.com/sitemap-posts.xml
22 | 2020-10-06T14:04:09.000Z
23 |
24 |
25 | `)
26 | })
27 |
28 | test(`#60 - How to add stylesheet for sitemap?`, () => {
29 | const doc = $$.create(
30 | { version: '1.0', encoding: 'UTF-8' },
31 | {
32 | '?': 'xml-stylesheet type="text/xsl" href="//example.com/sitemap.xsl"',
33 | sitemapindex: {
34 | '@xmlns': 'http://www.sitemaps.org/schemas/sitemap/0.9',
35 | sitemap: {
36 | loc: 'https://example.com/sitemap-posts.xml',
37 | lastmod: '2020-10-06T14:04:09.000Z'
38 | }
39 | }
40 | }).doc()
41 |
42 | expect(doc.end({prettyPrint: true })).toBe($$.t`
43 |
44 |
45 |
46 |
47 | https://example.com/sitemap-posts.xml
48 | 2020-10-06T14:04:09.000Z
49 |
50 |
51 | `)
52 | })
53 |
54 | })
55 |
--------------------------------------------------------------------------------
/test/issues/issue-067.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 | import { select } from "xpath";
3 |
4 | describe("Replicate issue", () => {
5 | // https://github.com/oozcitak/xmlbuilder2/issues/67
6 | test(`#67 - Xpath examples in documentation`, () => {
7 | const obj = {
8 | prop1: {
9 | prop2: 'Prop2Value',
10 | prop3: 'Prop3Value'
11 | }
12 | }
13 |
14 | let doc = $$.create({ encoding: "UTF-8" }, obj);
15 |
16 | let selected = select('//prop3', doc.node as any);
17 | expect((selected[0] as any).nodeName).toBe('prop3');
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/issues/issue-078.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | const obj = {
5 | title: {
6 | $: null
7 | },
8 | description: 'Test description'
9 | }
10 |
11 | // https://github.com/oozcitak/xmlbuilder2/issues/78
12 | test(`#78 - Throws TypeError: Cannot read property 'indexOf' of null when use null in CDATA ($)`, () => {
13 | const doc = $$.create()
14 | .ele('root').ele(obj).end({prettyPrint: true, headless: true })
15 |
16 | expect(doc).toBe($$.t`
17 |
18 |
19 | Test description
20 |
21 | `)
22 | })
23 |
24 | test(`#78 - Throws TypeError: Cannot read property 'indexOf' of null when use null in CDATA ($) - callback`, (done) => {
25 | const xmlStream = $$.createCB({ prettyPrint: true })
26 | .ele('root').ele(obj).end()
27 |
28 | $$.expectCBResult(xmlStream, $$.t`
29 |
30 |
31 |
32 | Test description
33 |
34 |
35 | `, done)
36 | })
37 |
38 | })
39 |
--------------------------------------------------------------------------------
/test/issues/issue-081.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/78
5 | test(`#81 - Using the .Up() method does not really move up to the parent node`, () => {
6 | const messageReference = $$.fragment().ele('MessageReference')
7 | .ele('MessageType').txt('4005').up()
8 | .ele('MessageTypeVersion').txt('5.3.1.GB').up()
9 | .ele('MessageIdentifier').txt('414d51204e52504230303920202020205e504839247eb882').up()
10 | .ele('MessageDateTime').txt('2021-03-18T17:27:54.562').up()
11 | .doc().end({ prettyPrint: true });
12 | const messageHeader = $$.fragment().ele('MessageHeader')
13 | .ele(messageReference).up()
14 | .ele('SenderReference').txt('1B25LMJp-H5K').up()
15 | .ele('Sender', { 'ns0:CI_InstanceNumber': '01' }).txt('0070').up()
16 | .ele('Recipient', { 'ns0:CI_InstanceNumber': '99' }).txt('9999').up()
17 | .doc().end({ prettyPrint: true });
18 | const doc = $$.create().ele('TrainRunningInformationMessage').att('xmlns:ns0', 'http://www.era.europa.eu/schemes/TAFTSI/5.3')
19 | .att('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance').att('xsi:schemaLocation', 'http://www.era.europa.eu/schemes/TAFTSI/5.3 taf_cat_complete.xsd')
20 | .ele(messageHeader).root()
21 | .ele('1 ').root()
22 | .doc();
23 |
24 | expect(doc.end({ prettyPrint: true })).toBe($$.t`
25 |
26 |
27 |
28 |
29 | 4005
30 | 5.3.1.GB
31 | 414d51204e52504230303920202020205e504839247eb882
32 | 2021-03-18T17:27:54.562
33 |
34 | 1B25LMJp-H5K
35 | 0070
36 | 9999
37 |
38 | 1
39 |
40 | `)
41 | })
42 |
43 | })
44 |
--------------------------------------------------------------------------------
/test/issues/issue-082.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/82
5 | test(`#82 - convert does not respect encoding`, () => {
6 | const obj = {
7 | xliff: {
8 | "@version": "1.2",
9 | file: {
10 | "@datatype": "plaintext",
11 | "@source-language": "en",
12 | body: {
13 | "@id": "test",
14 | source: " test "
15 | },
16 | },
17 | },
18 | }
19 | const objProcessed = {
20 | xliff: {
21 | "@version": "1.2",
22 | file: {
23 | "@datatype": "plaintext",
24 | "@source-language": "en",
25 | body: {
26 | "@id": "test",
27 | source: "<this> test </this>"
28 | },
29 | },
30 | },
31 | }
32 |
33 | const str = $$.convert(obj, { prettyPrint: true })
34 | const obj2 = $$.convert(str, { format: "object" })
35 | expect(obj2).toEqual(objProcessed)
36 | })
37 |
38 | })
39 |
--------------------------------------------------------------------------------
/test/issues/issue-088.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/88
5 | test(`#88 - DOM textContent returns encoded text`, () => {
6 | const xmlStr = $$.t`
7 |
8 |
9 | <data>
10 | ]]>
11 |
12 | `
13 |
14 | const doc = $$.create(xmlStr);
15 | expect(doc.root().first().first().node.textContent).toBe('')
16 | expect(doc.end({ headless: true, prettyPrint: true})).toBe($$.t`
17 |
18 | <data>
19 | ]]>
20 |
21 | `);
22 | })
23 |
24 | })
25 |
--------------------------------------------------------------------------------
/test/issues/issue-090.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/90
5 | test(`#90 - The Mixed Content example for Text Object Conversion does not work.`, () => {
6 | const obj2 = {
7 | monologue: {
8 | '#': [
9 | 'Talk to me Goose!',
10 | { 'cut': 'dog tag shot' },
11 | 'Talk to me...'
12 | ]
13 | }
14 | };
15 | const doc = $$.create().ele(obj2);
16 | expect(doc.end({ headless: true, prettyPrint: true})).toBe($$.t`
17 |
18 | Talk to me Goose!
19 | dog tag shot
20 | Talk to me...
21 |
22 | `);
23 | })
24 |
25 | })
26 |
--------------------------------------------------------------------------------
/test/issues/issue-098.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/98
5 | test(`#98 - When converting from xml string to js object, & might be double escaped`, () => {
6 | const xmlStr = $$.t`
7 | I'm <b>bold</b>
8 | `
9 |
10 | const obj = $$.create(xmlStr).end({ format: 'object' })
11 | expect(obj).toEqual(
12 | {
13 | description: "I'm <b>bold</b>"
14 | }
15 | )
16 | })
17 |
18 | })
19 |
--------------------------------------------------------------------------------
/test/issues/issue-099.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/99
5 | test(`#99 - Most XML entities not being decoded by reader (with unknown entity)`, () => {
6 | const xmlResponse = $$.create('Me & Myself's WiFi ©𝌆 ');
7 | const networkResponse = xmlResponse.end({format: 'object'});
8 | expect(networkResponse).toEqual({
9 | ssid: `Me & Myself's WiFi ©𝌆`
10 | })
11 | })
12 |
13 | test(`#99 - Most XML entities not being decoded by reader (without unknown entity)`, () => {
14 | const xmlResponse = $$.create('Me & Myself's WiFi 𝌆 ');
15 | const networkResponse = xmlResponse.end({format: 'object'});
16 | expect(networkResponse).toEqual({
17 | ssid: `Me & Myself's WiFi 𝌆`
18 | })
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/test/issues/issue-105.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from "../TestHelpers";
2 |
3 | describe("Replicate issue", () => {
4 | // https://github.com/oozcitak/xmlbuilder2/issues/90
5 | test(`#105 - Illegal character does not get sanitized.`, () => {
6 | const b = $$.create()
7 | b.ele('doc').ele('test').txt('some & text; foo')
8 | expect(b.end()).toBe($$.t`some & text; foo `);
9 | })
10 |
11 | })
12 |
--------------------------------------------------------------------------------
/test/readers/JSONReader.custom.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('custom JSONReader', () => {
4 |
5 | test('skip comments', () => {
6 | const json = `{
7 | "ele": "element",
8 | "!": "comment"
9 | }`
10 |
11 | const doc = $$.create({ parser: { comment: () => undefined } }).ele('root').ele(json).doc()
12 |
13 | expect($$.printTree(doc.node)).toBe($$.t`
14 | root
15 | ele
16 | # element
17 | `)
18 | })
19 |
20 | })
21 |
--------------------------------------------------------------------------------
/test/readers/ObjectReader.custom.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('custom ObjectReader', () => {
4 |
5 | test('skip comments', () => {
6 | const obj = {
7 | ele: 'element',
8 | '!': 'comment'
9 | }
10 |
11 | const doc = $$.create({ parser: { comment: () => undefined } }).ele('root').ele(obj).doc()
12 |
13 | expect($$.printTree(doc.node)).toBe($$.t`
14 | root
15 | ele
16 | # element
17 | `)
18 | })
19 |
20 | test('skip all nodes', () => {
21 | const obj = {
22 | ele: "simple element",
23 | person: {
24 | name: "John",
25 | '@': { 'age': 35, 'weight': 75 },
26 | '?': 'pi mypi',
27 | '!': 'Good guy',
28 | '$': 'well formed!',
29 | address: {
30 | '?': 'pi',
31 | city: "Istanbul",
32 | street: "End of long and winding road"
33 | },
34 | contact: {
35 | phone: ["555-1234", "555-1235"]
36 | },
37 | id: () => 42,
38 | details: {
39 | '#': 'classified'
40 | }
41 | }
42 | }
43 |
44 | const doc = $$.create({
45 | parser: {
46 | attribute: () => undefined,
47 | cdata: () => undefined,
48 | docType: () => undefined,
49 | element: () => undefined,
50 | instruction: () => undefined,
51 | text: () => undefined,
52 | comment: () => undefined
53 | }
54 | }).ele('root').ele(obj).doc()
55 |
56 | expect($$.printTree(doc.node)).toBe($$.t`
57 | root
58 | `)
59 | })
60 |
61 | test('custom sanitizer', () => {
62 | const obj = {
63 | ele: 'element\0',
64 | '!': '\0comment'
65 | }
66 |
67 | const doc = $$.create({ parser: { sanitize: () => "clean" } }).ele('root').ele(obj).doc()
68 |
69 | expect($$.printTree(doc.node)).toBe($$.t`
70 | root
71 | clean
72 | # clean
73 | ! clean
74 | `)
75 | })
76 |
77 | })
78 |
--------------------------------------------------------------------------------
/test/readers/XMLReader.custom.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { sanitizeInput } from '../../src/builder/dom'
3 |
4 | describe('custom XMLReader', () => {
5 |
6 | test('skip DocType', () => {
7 | const xml = $$.t`
8 |
9 |
10 | `
11 |
12 | const doc = $$.create({ parser: { docType: () => undefined } }, xml).doc()
13 | expect(doc.end()).toBe(' ')
14 | })
15 |
16 | test('skip all nodes', () => {
17 | const xml = $$.t`
18 |
19 |
20 |
21 | simple element
22 |
23 | John
24 |
25 |
26 |
27 |
28 |
29 | Istanbul
30 | End of long and winding road
31 |
32 |
33 | 555-1234
34 | 555-1235
35 |
36 | 42
37 | classified
38 |
39 |
40 | `
41 |
42 | const doc = $$.create({
43 | parser: {
44 | attribute: () => undefined,
45 | cdata: () => undefined,
46 | docType: () => undefined,
47 | element: () => undefined,
48 | instruction: () => undefined,
49 | text: () => undefined,
50 | comment: () => undefined
51 | }
52 | }).ele('root').ele(xml).doc()
53 |
54 | expect($$.printTree(doc.node)).toBe($$.t`
55 | root
56 | `)
57 | })
58 |
59 | test('skip DocType', () => {
60 | const xml = $$.t`
61 |
62 |
63 | `
64 |
65 | const doc = $$.create({ parser: { docType: () => undefined } }, xml).doc()
66 | expect(doc.end()).toBe(' ')
67 | })
68 |
69 | test("invalidCharReplacement should apply before parser functions", () => {
70 | const xml = `
71 |
72 |
73 |
74 |
75 | `
76 |
77 | const obj = $$.convert({
78 | invalidCharReplacement: '',
79 | parser: {
80 | element: (parent, ns, name: string) => {
81 | expect(sanitizeInput(name, '')).toBe(name)
82 | return parent.ele(name)
83 | }
84 | }
85 | }, xml, { format: 'object' })
86 | expect(obj).toEqual({
87 | root: {
88 | node1: {},
89 | node2: {}
90 | }
91 | })
92 | })
93 |
94 | test("skip whitespace only text", () => {
95 | const xml = $$.t`
96 |
97 |
98 |
99 | `
100 |
101 | const doc = $$.create({ skipWhitespaceOnlyText: true }, xml).doc()
102 | expect(doc.end()).toBe(` `)
103 | })
104 |
105 | test("retain whitespace only text", () => {
106 | const xml = $$.t`
107 |
108 |
109 |
110 | `
111 |
112 | const doc = $$.create({ skipWhitespaceOnlyText: false }, xml).doc()
113 |
114 | expect(doc.end()).toBe(
115 | $$.t`
116 |
117 |
118 |
119 | `)
120 | })
121 | })
122 |
--------------------------------------------------------------------------------
/test/readers/XMLReader.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('XMLReader', () => {
4 |
5 | test('invalid version', () => {
6 | const xml = $$.t`
7 |
8 |
9 | `
10 |
11 | expect(() => $$.create(xml)).toThrow()
12 | })
13 |
14 | test('docType', () => {
15 | const xml = $$.t`
16 |
17 |
18 |
19 | simple element
20 |
21 | John
22 |
23 |
24 |
25 |
26 |
27 | Istanbul
28 | End of long and winding road
29 |
30 |
31 | 555-1234
32 | 555-1235
33 |
34 | 42
35 | classified
36 |
37 |
38 | `
39 |
40 | const result = $$.create(xml).end({ prettyPrint: true })
41 | expect(result).toEqual(xml)
42 | })
43 |
44 | test('returned node should be the top level node', () => {
45 | const baz = $$.create().ele('Qroot').ele($$.t`
46 |
47 | foobar
48 |
49 |
50 | `);
51 |
52 | expect(baz.toString()).toBe(' ')
53 | })
54 |
55 | })
56 |
--------------------------------------------------------------------------------
/test/readers/YAMLReader.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('YAMLReader', () => {
4 |
5 | test('basic', () => {
6 | const yaml = $$.t`
7 | # yaml test
8 | %YAML 1.2
9 | # comment
10 | ---
11 | "root":
12 | "ele": "simple element"
13 | "person":
14 | "@age": "35"
15 | "name": "John"
16 | "?": "pi mypi"
17 | "!": "Good guy"
18 | "$": "well formed!"
19 | "address":
20 | "city": "Istanbul"
21 | "street": "End of long and winding road"
22 | "contact":
23 | "phone":
24 | - "555-1234"
25 | - "555-1235"
26 | "id": "42"
27 | "details": "classified"
28 | `
29 | const obj = {
30 | root: {
31 | ele: "simple element",
32 | person: {
33 | name: "John",
34 | '@age': '35',
35 | '?': 'pi mypi',
36 | '!': 'Good guy',
37 | '$': 'well formed!',
38 | address: {
39 | city: "Istanbul",
40 | street: "End of long and winding road"
41 | },
42 | contact: {
43 | phone: [ "555-1234", "555-1235" ]
44 | },
45 | id: '42',
46 | details: 'classified'
47 | }
48 | }
49 | }
50 |
51 | const result = $$.create(yaml).end({ format: "object" })
52 | expect(result).toEqual(obj)
53 | })
54 |
55 | test('empty document', () => {
56 | const doc = $$.create('---')
57 | expect(doc.end()).toBe('')
58 | })
59 |
60 | })
61 |
--------------------------------------------------------------------------------
/test/wiki/custom-parsers.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('custom parser examples in wiki', () => {
4 |
5 | test('skip comments', () => {
6 | const xmlString = `
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | `;
16 |
17 | const doc = $$.create({ parser: { comment: () => undefined } }, xmlString);
18 |
19 | expect(doc.end({ prettyPrint: true })).toBe($$.t`
20 |
21 |
22 |
23 |
24 |
25 |
26 | `)
27 | })
28 |
29 | test("namespace scope", () => {
30 | const obj = {
31 | 'root': {
32 | '-ns1:some/uri': { // namespace scope - prefix: ns1, ns: some/uri
33 | 'node1': '',
34 | 'node2': ''
35 | },
36 | '-': { // no namespace
37 | 'node3': ''
38 | }
39 | }
40 | }
41 |
42 | let prefix: string | undefined
43 | let ns: string | undefined
44 | const elementParser = function(this: any, parent: any, namespace: string | null | undefined, name: string): any | undefined {
45 | if (name.startsWith('-')) {
46 | let [elePrefix, eleNS] = name.substring(1).split(':')
47 | if (eleNS === undefined) {
48 | prefix = undefined
49 | ns = undefined
50 | return parent
51 | } else {
52 | prefix = elePrefix
53 | ns = eleNS
54 | return parent.att('xmlns:' + prefix, eleNS)
55 | }
56 | } else {
57 | return prefix ? parent.ele(prefix + ':' + name) : parent.ele(name)
58 | }
59 | }
60 |
61 | const doc = $$.create({ parser: { element: elementParser } }, obj);
62 |
63 | expect(doc.end({ headless: true, prettyPrint: true })).toBe($$.t`
64 |
65 |
66 |
67 |
68 |
69 | `)
70 | })
71 |
72 | })
73 |
74 |
--------------------------------------------------------------------------------
/test/wiki/functions-EventEmitter.test.out:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/wiki/functions-callback.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { createWriteStream, readFile } from 'fs'
3 | import { resolve } from 'path'
4 | import { createCB, fragmentCB } from '../../src'
5 |
6 | describe('examples in the callback function reference wiki page', () => {
7 |
8 | test('documentCB()', (done) => {
9 | const filename = resolve(__dirname, 'functions-documentCB.test.out')
10 | const outFile = createWriteStream(filename)
11 |
12 | const xmlStream = createCB({
13 | 'data': (chunk: string) => outFile.write(chunk),
14 | 'end': () => outFile.end()
15 | })
16 |
17 | outFile.on('close', () => {
18 | readFile(filename, 'utf8', (err, result) => {
19 | expect(result).toBe(' ')
20 | done()
21 | })
22 | })
23 |
24 | xmlStream.ele("root")
25 | .ele("foo").up()
26 | .ele("bar").att("fizz", "buzz").up()
27 | .end()
28 | })
29 |
30 | test('fragmentCB()', (done) => {
31 | const filename = resolve(__dirname, 'functions-fragmentCB.test.out')
32 | const outFile = createWriteStream(filename)
33 |
34 | const xmlStream = fragmentCB({
35 | 'data': (chunk: string) => outFile.write(chunk),
36 | 'end': () => outFile.end()
37 | })
38 |
39 | outFile.on('close', () => {
40 | readFile(filename, 'utf8', (err, result) => {
41 | expect(result).toBe(' ')
42 | done()
43 | })
44 | })
45 |
46 | xmlStream.ele("foo").up()
47 | .ele("foo").att("fizz", "buzz").up()
48 | .ele("foo").up()
49 | .end()
50 | })
51 |
52 | test('EventEmitter', (done) => {
53 | const filename = resolve(__dirname, 'functions-EventEmitter.test.out')
54 | const outFile = createWriteStream(filename)
55 |
56 | const xmlStream = createCB()
57 | xmlStream.on('data', (chunk) => outFile.write(chunk))
58 | xmlStream.on('end', () => outFile.end())
59 |
60 | outFile.on('close', () => {
61 | readFile(filename, 'utf8', (err, result) => {
62 | expect(result).toBe(' ')
63 | done()
64 | })
65 | })
66 |
67 | xmlStream.ele("root")
68 | .ele("foo").up()
69 | .ele("bar").att("fizz", "buzz").up()
70 | .end()
71 | })
72 |
73 | })
74 |
--------------------------------------------------------------------------------
/test/wiki/functions-documentCB.test.out:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/wiki/functions-fragmentCB.test.out:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/wiki/functions.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('examples in the function reference wiki page', () => {
4 |
5 | test('document()', () => {
6 | const doc1 = $$.create()
7 | expect(doc1.end()).toBe('')
8 |
9 | const doc2 = $$.create({ version: "1.0" })
10 | expect(doc2.end()).toBe('')
11 |
12 | const doc3 = $$.create('foobar ')
13 | expect(doc3.end({ headless: true }))
14 | .toBe('foobar ')
15 | })
16 |
17 | test('fragment()', () => {
18 | const frag1 = $$.fragment()
19 | expect(frag1.toString()).toBe('')
20 |
21 | const frag2 = $$.fragment({ version: "1.0" })
22 | expect(frag2.toString()).toBe('')
23 |
24 | const frag3 = $$.fragment('bar baz ')
25 | expect(frag3.toString())
26 | .toBe('bar baz ')
27 | })
28 |
29 | test('ele()', () => {
30 | const doc1 = $$.create()
31 | .ele("http://myschema.com", "m:root", { "att1": "value1", "att2": "value2" })
32 | expect(doc1.end({ prettyPrint: true, headless: true }))
33 | .toBe(' ')
34 |
35 | const doc2 = $$.create()
36 | .ele("root", { "att1": "value1", "att2": "value2" })
37 | expect(doc2.end({ prettyPrint: true, headless: true }))
38 | .toBe(' ')
39 |
40 | const doc3 = $$.create()
41 | .ele({ "root": { "@att1": "value1", "@att2": "value2", "#": "text" }})
42 | expect(doc3.end({ prettyPrint: true, headless: true }))
43 | .toBe('text ')
44 | })
45 |
46 | })
47 |
--------------------------------------------------------------------------------
/test/wiki/home.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('examples in the home wiki page', () => {
4 |
5 | test('example with ele', () => {
6 | const xmlStr = $$.t`
7 |
8 |
9 |
10 | foobar
11 |
12 |
13 |
14 | `
15 | const doc = $$.create({ version: "1.0" })
16 | .ele("root", { att: "val" })
17 | .ele("foo")
18 | .ele("bar").txt("foobar").up()
19 | .up()
20 | .ele("baz")
21 | .doc()
22 |
23 | expect(doc.end({ prettyPrint: true })).toBe(xmlStr)
24 | })
25 |
26 | test('example with JS object', () => {
27 | const xmlStr = $$.t`
28 |
29 |
30 |
31 | foobar
32 |
33 |
34 |
35 | `
36 | const doc = $$.create({ version: "1.0" }, {
37 | root: {
38 | "@att": "val",
39 | "foo": {
40 | "bar": "foobar"
41 | },
42 | "baz": {}
43 | }
44 | })
45 |
46 | expect(doc.end({ prettyPrint: true })).toBe(xmlStr)
47 | })
48 |
49 | test('example with parser', () => {
50 | const xmlStr1 = $$.t`
51 |
52 |
53 |
54 | foobar
55 |
56 |
57 | `
58 | const xmlStr2 = $$.t`
59 |
60 |
61 |
62 | foobar
63 |
64 |
65 |
66 | `
67 | const doc = $$.create(xmlStr1)
68 | doc.root().ele("baz")
69 | expect(doc.end({ prettyPrint: true })).toBe(xmlStr2)
70 | })
71 |
72 | })
73 |
--------------------------------------------------------------------------------
/test/wiki/upgrading.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 |
3 | describe('upgrading from xmlbuilder examples in wiki', () => {
4 |
5 | test('JS object conversion syntax of CDATA section nodes is changed', () => {
6 | const xml1 = $$.create().ele("root").ele({ "$": "value" }).end({ format: "xml" })
7 | expect(xml1).toEqual(` `)
8 | const xml2 = $$.create({ convert: { text: '#text', cdata: '#cdata' } }).ele("root").ele({ "#cdata": "value" }).end({ format: "xml" })
9 | expect(xml2).toEqual(` `)
10 | })
11 |
12 | test('JS object conversion syntax of comment nodes is changed', () => {
13 | const xml1 = $$.create().ele("root").ele({ "!": "value" }).end({ format: "xml" })
14 | expect(xml1).toEqual(` `)
15 | const xml2 = $$.create({ convert: { text: '#text', comment: '#comment' } }).ele("root").ele({ "#comment": "value" }).end({ format: "xml" })
16 | expect(xml2).toEqual(` `)
17 | })
18 |
19 | })
20 |
21 |
--------------------------------------------------------------------------------
/test/xpath/namespace.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { select } from 'xpath'
3 |
4 | describe('XPath with Namespaces', () => {
5 |
6 | test('select', () => {
7 | const doc = $$.create("Harry Potter ")
8 | const node = select("//*[local-name(.)='title' and namespace-uri(.)='myns']", doc.node as any) as any
9 |
10 | expect(node[0].namespaceURI).toBe("myns")
11 | })
12 |
13 | })
14 |
--------------------------------------------------------------------------------
/test/xpath/simple.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { select, select1 } from 'xpath'
3 |
4 | describe('Simple XPath', () => {
5 |
6 | test('select 1', () => {
7 | const doc = $$.create().ele('book').ele('title').txt('Harry Potter').doc()
8 | const nodes = select('//title', doc.node as any) as any
9 |
10 | expect(nodes[0].localName).toBe("title")
11 | expect(nodes[0].firstChild.data,).toBe("Harry Potter")
12 | expect($$.builder(nodes[0]).toString()).toBe("Harry Potter ")
13 | })
14 |
15 | test('select 2', () => {
16 | const doc = $$.create()
17 | .ins('book', 'title="Harry Potter"')
18 | .ins('series', 'title="Harry Potter"')
19 | .ins('series', 'books="7"')
20 | .ele('root')
21 | .com('This is a great book')
22 | .ele('title')
23 | .txt('Harry Potter')
24 | .doc()
25 |
26 | const nodes = select('//title', doc.node as any) as any
27 | const nodes2 = select('//node()', doc.node as any) as any
28 | const pis = select("/processing-instruction('series')", doc.node as any) as any
29 |
30 | expect(nodes[0].localName).toBe('title')
31 | expect(nodes[0].firstChild.data).toBe('Harry Potter')
32 | expect($$.builder(nodes[0]).toString()).toBe('Harry Potter ')
33 |
34 | expect(nodes2.length).toBe(7)
35 |
36 | expect(pis.length).toBe(2)
37 | expect(pis[1].data).toBe('books="7"')
38 | })
39 |
40 | test('Select single node', () => {
41 | const doc = $$.create().ele('book').ele('title').txt('Harry Potter').doc()
42 | const nodes = select('//title[1]', doc.node as any) as any
43 | expect(nodes[0].localName).toBe('title')
44 | })
45 |
46 | test('Select text node', () => {
47 | const doc = $$.create().ele('book').ele('title').txt('Harry').up().ele('title').txt('Potter').doc()
48 | expect(select('local-name(/book)', doc.node as any) as any).toBe('book')
49 | expect($$.builder(select('//title/text()', doc.node as any) as any).toString()).toBe('Harry,Potter')
50 | })
51 |
52 | test('Select number value', () => {
53 | const doc = $$.create().ele('book').ele('title').txt('Harry').up().ele('title').txt('Potter').doc()
54 | expect(select('count(//title)', doc.node as any)).toBe(2)
55 | })
56 |
57 | test('Select attribute', () => {
58 | const doc = $$.create().ele('author').att('name', 'J. K. Rowling').doc()
59 | const author = select1('/author/@name', doc.node as any) as any
60 | expect(author.value).toBe('J. K. Rowling')
61 | })
62 |
63 | test('Select with multiple predicates', () => {
64 | const doc = $$.create().ele('characters')
65 | .ele('character', { name: "Snape", sex: "M", age: "50" }).up()
66 | .ele('character', { name: "McGonnagal", sex: "F", age: "65" }).up()
67 | .doc()
68 |
69 | const characters = select('/*/character[@sex = "M"][@age > 40]/@name', doc.node as any) as any
70 |
71 | expect(characters.length).toBe(1)
72 | expect(characters[0].textContent).toBe('Snape')
73 | })
74 |
75 | })
76 |
--------------------------------------------------------------------------------
/test/xsd/simple.test.ts:
--------------------------------------------------------------------------------
1 | import $$ from '../TestHelpers'
2 | import { parseXml } from 'libxmljs2'
3 |
4 | describe('Simple XSD validation', () => {
5 |
6 | test('XSD validation', () => {
7 | const xsdDoc = $$.create()
8 | .ele('xs:schema', { 'xmlns:xs': 'http://www.w3.org/2001/XMLSchema' })
9 | .ele('xs:element', { name: 'book' }).doc()
10 | const xmlDoc1 = $$.create().ele('book').doc()
11 | const xmlDoc2 = $$.create().ele('booze').doc()
12 |
13 | const xsd = parseXml(xsdDoc.end() as string)
14 |
15 | const xml1 = parseXml(xmlDoc1.end() as string)
16 | const xml2 = parseXml(xmlDoc2.end() as string)
17 |
18 | expect(xml1.validate(xsd)).toBe(true)
19 | expect(xml2.validate(xsd)).toBe(false)
20 | })
21 |
22 | })
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES5",
4 | "module": "CommonJS",
5 | "declaration": true,
6 | "lib": [
7 | "ES5"
8 | ],
9 | "downlevelIteration": true,
10 | "locale": "en",
11 | "strict": true,
12 | "newLine": "lf",
13 | "sourceMap": true,
14 | "esModuleInterop": true,
15 | "outDir": "lib",
16 | "types": [
17 | "node",
18 | "jest",
19 | "dedent"
20 | ]
21 | },
22 | "include": [
23 | "src/**/*"
24 | ],
25 | "exclude": [
26 | "node_modules"
27 | ]
28 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.ts',
5 | // devtool: 'inline-source-map',
6 | mode: 'production', // production | development
7 | node: {
8 | global: true,
9 | __filename: false,
10 | __dirname: false,
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.tsx?$/,
16 | use: [
17 | {
18 | loader: 'babel-loader',
19 | options: {
20 | sourceType: "unambiguous",
21 | presets: [
22 | [
23 | '@babel/preset-env',
24 | {
25 | useBuiltIns: "usage",
26 | modules: false,
27 | corejs: 3,
28 | //debug: true,
29 | targets: {
30 | browsers: [
31 | "defaults",
32 | "ie >= 11"
33 | ]
34 | }
35 | }
36 | ]
37 | ]
38 | },
39 | },
40 | { loader: 'ts-loader' }
41 | ],
42 | exclude: /node_modules/
43 | },
44 | ],
45 | },
46 | resolve: {
47 | extensions: [ '.tsx', '.ts', '.js' ],
48 | },
49 | output: {
50 | filename: 'xmlbuilder2.min.js',
51 | path: path.resolve(__dirname, 'lib'),
52 | library: 'xmlbuilder2',
53 | libraryTarget: 'umd',
54 | globalObject: 'this'
55 | }
56 | };
--------------------------------------------------------------------------------