Add support for using single quotes to enclose attribute values
This change adds format_attribute_single_quote flag that uses single quotes (`'`) instead of double quotes (`"`) for formatting attribute values. Internal quotation marks are escaped using `"` and `'`.
This commit is contained in:
parent
fcb7c8d3e5
commit
5a867cb1e3
@ -1706,6 +1706,8 @@ These flags control the resulting tree contents:
|
|||||||
|
|
||||||
* [[format_skip_control_chars]]`format_skip_control_chars` enables skipping characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is *off* by default.
|
* [[format_skip_control_chars]]`format_skip_control_chars` enables skipping characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is *off* by default.
|
||||||
|
|
||||||
|
* [[format_attribute_single_quote]]`format_attribute_single_quote` enables using single quotes `'` instead of double quotes `"` for enclosing attribute values. This flag is *off* by default.
|
||||||
|
|
||||||
These flags control the additional output information:
|
These flags control the additional output information:
|
||||||
|
|
||||||
* [[format_no_declaration]]`format_no_declaration` disables default node declaration output. By default, if the document is saved via `save` or `save_file` function, and it does not have any document declaration, a default declaration is output before the document contents. Enabling this flag disables this declaration. This flag has no effect in `xml_node::print` functions: they never output the default declaration. This flag is *off* by default.
|
* [[format_no_declaration]]`format_no_declaration` disables default node declaration output. By default, if the document is saved via `save` or `save_file` function, and it does not have any document declaration, a default declaration is output before the document contents. Enabling this flag disables this declaration. This flag has no effect in `xml_node::print` functions: they never output the default declaration. This flag is *off* by default.
|
||||||
|
|||||||
@ -3327,6 +3327,9 @@ You should use the usual bitwise arithmetics to manipulate the bitmask: to enabl
|
|||||||
<li>
|
<li>
|
||||||
<p><a id="format_skip_control_chars"></a><code>format_skip_control_chars</code> enables skipping characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is <strong>off</strong> by default.</p>
|
<p><a id="format_skip_control_chars"></a><code>format_skip_control_chars</code> enables skipping characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is <strong>off</strong> by default.</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a id="format_attribute_single_quote"></a><code>format_attribute_single_quote</code> enables using single quotes <code>'</code> instead of double quotes <code>"</code> for enclosing attribute values. This flag is <strong>off</strong> by default.</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
|
|||||||
@ -1861,7 +1861,7 @@ PUGI__NS_BEGIN
|
|||||||
enum chartypex_t
|
enum chartypex_t
|
||||||
{
|
{
|
||||||
ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
|
ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
|
||||||
ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, >, "
|
ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, >, ", '
|
||||||
ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
|
ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
|
||||||
ctx_digit = 8, // 0-9
|
ctx_digit = 8, // 0-9
|
||||||
ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
|
ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
|
||||||
@ -1871,7 +1871,7 @@ PUGI__NS_BEGIN
|
|||||||
{
|
{
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
|
||||||
0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
|
0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
|
||||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63
|
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63
|
||||||
|
|
||||||
0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
|
0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
|
||||||
@ -3933,6 +3933,10 @@ PUGI__NS_BEGIN
|
|||||||
writer.write('&', 'q', 'u', 'o', 't', ';');
|
writer.write('&', 'q', 'u', 'o', 't', ';');
|
||||||
++s;
|
++s;
|
||||||
break;
|
break;
|
||||||
|
case '\'':
|
||||||
|
writer.write('&', 'a', 'p', 'o', 's', ';');
|
||||||
|
++s;
|
||||||
|
break;
|
||||||
default: // s is not a usual symbol
|
default: // s is not a usual symbol
|
||||||
{
|
{
|
||||||
unsigned int ch = static_cast<unsigned int>(*s++);
|
unsigned int ch = static_cast<unsigned int>(*s++);
|
||||||
@ -4064,6 +4068,7 @@ PUGI__NS_BEGIN
|
|||||||
PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
|
PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
|
||||||
{
|
{
|
||||||
const char_t* default_name = PUGIXML_TEXT(":anonymous");
|
const char_t* default_name = PUGIXML_TEXT(":anonymous");
|
||||||
|
const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"';
|
||||||
|
|
||||||
for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
|
for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
|
||||||
{
|
{
|
||||||
@ -4079,12 +4084,12 @@ PUGI__NS_BEGIN
|
|||||||
}
|
}
|
||||||
|
|
||||||
writer.write_string(a->name ? a->name + 0 : default_name);
|
writer.write_string(a->name ? a->name + 0 : default_name);
|
||||||
writer.write('=', '"');
|
writer.write('=', enquotation_char);
|
||||||
|
|
||||||
if (a->value)
|
if (a->value)
|
||||||
text_output(writer, a->value, ctx_special_attr, flags);
|
text_output(writer, a->value, ctx_special_attr, flags);
|
||||||
|
|
||||||
writer.write('"');
|
writer.write(enquotation_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -255,6 +255,9 @@ namespace pugi
|
|||||||
// Skip characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is off by default.
|
// Skip characters belonging to range [0; 32) instead of "&#xNN;" encoding. This flag is off by default.
|
||||||
const unsigned int format_skip_control_chars = 0x100;
|
const unsigned int format_skip_control_chars = 0x100;
|
||||||
|
|
||||||
|
// Use single quotes ' instead of double quotes " for enclosing attribute values. This flag is off by default.
|
||||||
|
const unsigned int format_attribute_single_quote = 0x200;
|
||||||
|
|
||||||
// The default set of formatting flags.
|
// The default set of formatting flags.
|
||||||
// Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
|
// Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
|
||||||
const unsigned int format_default = format_indent;
|
const unsigned int format_default = format_indent;
|
||||||
|
|||||||
@ -193,7 +193,7 @@ TEST_XML(write_escape, "<node attr=''>text</node>")
|
|||||||
doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
|
doc.child(STR("node")).attribute(STR("attr")) = STR("<>'\"&\x04\r\n\t");
|
||||||
doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
|
doc.child(STR("node")).first_child().set_value(STR("<>'\"&\x04\r\n\t"));
|
||||||
|
|
||||||
CHECK_NODE(doc, STR("<node attr=\"<>'"& 	\"><>'\"&\r\n\t</node>"));
|
CHECK_NODE(doc, STR("<node attr=\"<>'"& 	\"><>'\"&\r\n\t</node>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_XML(write_escape_roundtrip, "<node attr=''>text</node>")
|
TEST_XML(write_escape_roundtrip, "<node attr=''>text</node>")
|
||||||
@ -207,7 +207,7 @@ TEST_XML(write_escape_roundtrip, "<node attr=''>text</node>")
|
|||||||
|
|
||||||
// Note: this string is almost identical to the string from write_escape with the exception of \r
|
// Note: this string is almost identical to the string from write_escape with the exception of \r
|
||||||
// \r in PCDATA doesn't roundtrip because it has to go through newline conversion (which could be disabled, but is active by default)
|
// \r in PCDATA doesn't roundtrip because it has to go through newline conversion (which could be disabled, but is active by default)
|
||||||
CHECK_NODE(doc, STR("<node attr=\"<>'"& 	\"><>'\"&\n\t</node>"));
|
CHECK_NODE(doc, STR("<node attr=\"<>'"& 	\"><>'\"&\n\t</node>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_XML(write_escape_unicode, "<node attr='㰀'/>")
|
TEST_XML(write_escape_unicode, "<node attr='㰀'/>")
|
||||||
@ -632,7 +632,7 @@ TEST_XML(write_no_empty_element_tags, "<node><child1/><child2>text</child2><chil
|
|||||||
|
|
||||||
TEST_XML_FLAGS(write_roundtrip, "<node><child1 attr1='value1' attr2='value2'/><child2 attr='value'>pre<![CDATA[data]]>mid<text&escape<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>", parse_full)
|
TEST_XML_FLAGS(write_roundtrip, "<node><child1 attr1='value1' attr2='value2'/><child2 attr='value'>pre<![CDATA[data]]>mid<text&escape<!--comment--><test/>post<?pi value?>fin</child2><child3/></node>", parse_full)
|
||||||
{
|
{
|
||||||
const unsigned int flagset[] = { format_indent, format_raw, format_no_declaration, format_indent_attributes, format_no_empty_element_tags };
|
const unsigned int flagset[] = { format_indent, format_raw, format_no_declaration, format_indent_attributes, format_no_empty_element_tags, format_attribute_single_quote };
|
||||||
size_t flagcount = sizeof(flagset) / sizeof(flagset[0]);
|
size_t flagcount = sizeof(flagset) / sizeof(flagset[0]);
|
||||||
|
|
||||||
for (size_t i = 0; i < (size_t(1) << flagcount); ++i)
|
for (size_t i = 0; i < (size_t(1) << flagcount); ++i)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user