Erik Naggum on Attributes in SGML, XML, Lisp (2001)
schnada.de
schnada.de
But here's the thing: XML is all about agreement. The value is not found at the syntactic level, where needless irregularities exit. The value is that more than a critical mass of agreement formed, and this agreement allowed the development of tools and standards useful across industries. Moreover, the low-level agreement on XML has enabled higher level agreement on vocabularies and grammars in many disparate sectors.
Sure, if you had a clean slate you could improve many parts of the XML standards. Consider, for example, XML Schema (XSD). The irregularities and complexity there are similarly annoying. I'd much rather write RELAX schemas. However, whole sectors have selected XML Schema and developed vocabularies and grammars whose value isn't found at the syntactical level; it's found in the agreement reflected in the decisions over vocabulary and grammar made by disparate groups striving to develop a common exchange mechanism.
Quibbles over syntax miss XML's real merit: XML enables agreement in developing vocabularies and grammars.
Apropos: Here's my Stack Overflow answer to the question of when to use XML attributes vs elements, written in XML for fun: http://stackoverflow.com/a/23133755/290085
The problem is beneath that: XML's semantics are tremendously large while also being a complete mess. The upshot is that the difficulty of being a compliant adopter---of matching such a large, nebulous, incompletely defined set of inconsistencies---is tremendous and instead there are leagues of partial, massively inconsistent consumers and producers who hammer out successful communication via a list of patches.
To some degree this situation was inevitable, but XML exacerbates it and cements the pattern.
In one sense, XML itself is semantically neutral. The association between elements/attributes names and real world objects is merely suggestive.
In another sense (that of semantic analysis found in compiler design), validating XML parsers could be said to be enforcing semantics expressed in schemas. I suppose it is in this sense that your objection applies. In the case of XML Schemas or DTDs, I would have to agree. You might find RELAX NG to be less of a semantic mess given its basis in finite tree automata.
The issue at hand where attributes and elements can serve very similar purpose is a great example. In a technical sense XML does not suggest anything about the relative meaning of these two bits, but with near universal acclaim they're used as "metadata" and "child data" whatever the speaker might believe those to mean.
In spiritually embracing TIMTOWTDI, XML has created a playing field where semantics are by default ambiguous and have to fight their way out of that disadvantage.
In some sense, XML-without-semantics has too much structure and this creates a minefield for laying meaning atop it.
I was about halfway through writing the (write-to-xml) function when I realised I could just write the entire lisp expression to the file instead...
Not only was it smaller, it had the huge advantage of not needing to parse it back when I wanted to read from disk, I just called the inbuilt (read) function. Thankfully I only wasted an afternoon!
That's what really ingrained the whole "data is code, code is data" idea into me. I even went on to write the structure function to each file as well, so that no matter what I did to the data structure down the line, I would still have the actual code needed to understand it. Right next to the data itself. Not only was my code self-documenting, my data was as well ;)
Every language I've ever used has variable assignment and you can write those to a document and execute it.
http://okmij.org/ftp/Scheme/xml.html
http://homepages.inf.ed.ac.uk/wadler/papers/xml-essence/xml-...
A choice quote from the latter:
> So the essence of XML is this: the problem it solves is not hard, and it does not solve the problem well.
And, again, if you really need it, the available third dimension provided by XML namespacing is a life-saver when you need it, and incredibly redundant when you don't.
I often dislike the phrase "Use the right tool for the job", because it is vacuous when not tied to some sort of suggestion on how you should determine what the right tool is, so: Match the dimensionality of your data to the dimensionality of the serialization format. The vast bulk of stuff you will encounter day-to-day is one dimensional and fits in JSON or a friend just fine. Use that. A nontrivial quantity of things fits into XML, mostly delimited text; use XML then. Every once in a while you need modularity in your XML format... do not reinvent XML namespaces, use them. (This is mostly for BIG standards, like XMPP or XHTML.) Use neither more nor less than what you need.
<foo bar="zot">quux</foo>
should be read as
(foo (bar "zot") "quux")
and most definitely _NOT_ as ((:foo :bar "zot") "quux")
Erik has this exactly backwards. His rendering is ambiguous: it does not distinguish <foo bar="zot"/> from <foo><bar>zot</bar></foo> (as he himself implicitly acknowledges later in the post). Also, rendering unqualified tags as keywords makes it easier to deal with namespaces.IMHO the Right Way to render <foo bar="zot">quux</foo> is ((:foo :bar "zot") "quux") with the further qualification that if there are no tags then ((:foo) "quux") can be simplfied to (:foo "quux"). This preserves a 1-1 correspondence between XML and sexprs, which is IMHO a requirement (in fact, the only requirement) for a reasonable mapping. If you have a 1-1 correspondence then you can freely convert back and forth between the two. If you don't, then you can't.
Alternatively you could also write (foo ((bar "zot)) quux) as it is handled in Racket's X-expressions, which has the distinct advantage that the symbol/identifier foo is not nested one level deeper, which makes reading it harder, while still preserving the 1-1 correspondence. Though in this case the meta-information is the first argument instead of being part of the identifier. It also works perfectly with stuff like <foo bar="zot" baz="zor">quux</foo>, which is read as (foo ((bar zot) (baz zor)) quux). I personally think this is way better than ((:foo :bar "zot" :baz "zor) "quux")
Why is that an advantage?
I actually like the aesthetics of the extra parens in the CAR. It provides a clear visual distinction between code and markup (at least in Common Lisp, where ((...) ...) is defined by the standard to be a syntax error) which I think is a feature. e.g.:
((:div :class "toplevel" :style "display:block")
(:h1 "This is a heading")
"This is content")
I think it looks kinda nice.No matter how you slice it, Erik is wrong here. His translation is lossy, and a lossy translation is bad because it can't be applied bidirectionally.
His very first sentence is:
As long as we think aloud in alternative syntaxes, I actually prefer to
break the _incredibly_ stupid syntactic-only separation of elements and
attribute values.
His entire post is a hypothetical in which you 1) need a structured markup language and 2) are willing to break compatibility with XML.<input type=button/>
and
<input><type>button</type></input>
Tags compose in different ways than attributes, that difference reflects a real aspect of the structure of the problem, and hence it's useful.
((foo baz bar) bing)
and
(foo (baz bar) bing)
The only difference is in the location of a single paren. But latter representation (Erik's) loses information whereas the former does not. All else being equal, and absent a compelling argument why the lost information has no value, it is better not to lose information.
2) The idea that it's "better not to lose information" is totally nonsensical because the value of information is contextual. For example, the ascii encoding of this message useful omits the subtleties of my awful handwriting, although you're right: it would be better to preserve the information present in the deep pencil strokes, indicating my frustrating with this thread.
Yes he is:
"I have come to _loathe_ the half-assed hybrid that some XML-in-Lisp tools use and produce"
> The idea that it's "better not to lose information" is totally nonsensical
You are knocking down a straw man. I didn't say that is it better not to lose information, full stop. I said "All else being equal, and absent a compelling argument why the lost information has no value" it is better not to lose information. In the case of your handwriting, all else is not equal.
https://groups.google.com/d/msg/comp.lang.lisp/8eUxiibm_zA/i...
"Whether bar is an attribute or a sub-element of foo is irrelevant to processing them."
I disagree. Elements and attributes compose in different ways, and I think this distinction is useful and hence relevant. I think it is self-evident that:
<input type=button/>
and
<input><type>button</type></input>
mean different things, and that it is legitimate to try to express either of these things, and so distinguishing between these two different things is useful.
In particular, the latter representation implies that:
<input>foo</input> <type>bar</type>
might mean something. The former representation makes it explicit that the type attribute is intended to be inextricably bound to the input tag. I think that's useful information.
Neither <input type=button/> nor <input><type>button</type></input> does mean anything without a spec of your language, and trying to infer that <input>foo</input> or <type>bar</type> is valid is only due to some pre-conception about the underlying semantics you gave to your data (you chose familiar tag names, after all).
If I gave you a sample XML file from work, you'd have a very hard time knowing whether one attribute/element is or isn't optional (or bound) to an element. You'd need a schema/meta-model or even an informal spec.
With attributes/elements, you have two ways of defining data where only one is necessary: (input (type button)). The closet example I can think of is for example, if you had a lisp that is not homoiconic but had two different syntaxes for lists at its core: [] and (), without a simple way to abstract over them. Then your data format would be cumbersome to use with no added benefit: whether or not a []-list means something different than a ()-list depends on the specification of your data.
Could be. The comment format demands a certain succinctness.
> Neither <input type=button/> nor <input><type>button</type></input> does mean anything without a spec of your language, and trying to infer that <input>foo</input> or <type>bar</type> is valid is only due to some pre-conception about the underlying semantics you gave to your data (you chose familiar tag names, after all).
Yes, that's true. Semantics is ultimately a very deep rabbit hole. My main claim is that it's useful to have an unambiguous syntactic distinction between data and metadata so that you can tell that the BAZ in <FOO BAZ=BAR>BING</FOO> is INTENDED to be a MODIFIER for FOO and NOT part of the CONTENT that FOO is marking up.
Actually, let me try to be excruciatingly precise: my claim is that it is not self-evident that a syntactic distinction between data and metadata is useless. Hence a rendering of XML into sexprs that preserves this distinction is defensible, and dismissing it in the pejorative terms that Erik uses is not justified.
> [...] is INTENDED to be a MODIFIER for FOO and NOT part of the CONTENT that FOO is marking up
"The intended use has less to do with it than the notion that you can define what is meta-information and what is information at the time you want to decide whether something goes in an attribute or a sub-element. My argument is that this is impossible. Whether it is meta-information or information is a reflection of the actual use, not the intended use.
However, given that the mechanism was created, and I will argue that it was not so much created as it was never thought possible to be any other way, it was used to define several language properties. "Now that we have this, would it not also be nice to have that." This means that several of the attribute types grew very far apart from the contents of sub-elements and you sort of "had" to use them as attributes, but only sort of, because the application can and does define the semantics of everything, and if you want ID and IDREF, you can make the same choice as you would in Common Lisp to use symbols or a hash tables of strings."
> Actually, let me try to be excruciatingly precise: my claim is that it is not self-evident that a syntactic distinction between data and metadata is useless. Hence a rendering of XML into sexprs that preserves this distinction is defensible, and dismissing it in the pejorative terms that Erik uses is not justified.
"No, there is nothing that requires there to be element attributes as a distinct concept from element contents. There are, however, a number of practical things that follow from making that arbitrar distinction which can look like rationales, but if you ask yourself "why can it not be a subelement", there are no real answers, only appeals to the idea that there somehow __have to be a distinction. It took me years to figure out that the whole attribute idea is completely vacuous, and I worked with the creator of SGML himself for several years on several SGML-related standards and projects. I started writing "A conceptual introduction to SGML" back in 1994, but as I had pained my way through five chapters, I had to realize that it was all wrong. There was a basic design mistake in the whole language framework. That mistake is that simply put: "what is good enough for the users of the language is not good enough for its creators". Each and every level of "containership" in SGML has its own syntax, optimized for the task. Each and every level has a different syntax for "the writing on the box" as opposed to "the contents of the box". This follows from a very simple, yet amazingly elusive principle in its design: Meta-data is conceptually incompatible with data. This is in fact wrong. Meta-data is only data viewed from a different angle, and vice versa. SGML forces you to remain loyal to your chosen angle of view."
So, the opinion seems to be that the arbitrary structure you put between meta-data and data at the moment you create data is not necessarly well-suited for people using your data: then, despite being useful, the syntactic distinction becomes an annoyance.
By the way, Erik's dissmissal is (1) the result of years of experience working on SGML, and (2) not pejorative, but argumented. He is the one arguing against the "self-evidence" of attributes.
Sorry, the phrase "incredibly stupid" is pejorative.
And I don't really care if his position is the result of years of experience. It's wrong nonetheless. There are certainly stupid things in SGML, but the attribute/element distinction is not one of them. (Or at least, it's not a no-brainer that this is one of the stupid things in SGML, so if you're going to claim that the attribute/element distinction is stupid you need to provide a cogent argument to support your position and not just proclaim it as self-evidently true.)
The <|> syntax is also absolutely non-ambiguous.
It seems to me that the fact that people can't even agree whether he actually meant P or ~P ought to call his wisdom (or at least his ability to communicate) into question.
I'm fairly certain that the reason he handles the pathological cases is so that he may interface with other people's XML specs. One can hate the design while meaningfully working with others, right?
By the way, it is an S expression. He uses the empty symbol || as a delimiter for the pathological cases. Furthermore, the Enamel syntax he describes is a reader macro; whether you think that is OK is up to your own personal aesthetics, but it is just an alternative syntax for lists (not everything has to syntactically be an S-expression, after all).
You (lisper) keep mentioning that there is a distinction between metadata and data, and you mention that composibility is the big distinction. However, as far as I can tell, you can compose child elements in an ordered sequence which you can't do with attributes (though you can append sets of attributes as sets), and you can't nest attributes. It seems to me that the only reason for everything not to be elements is that they take longer to type with XML syntax. Also, child elements are in some sense just attributes with implicit numeric keys, if attributes could be data other than strings.
What is an example of this distinction between attributes and elements which is not just syntax?
Yes. And I'm saying he's wrong. Not only is he wrong, he's clearly wrong. Not only is it not "incredibly stupid", the distinction between attributes and elements is both reasonable and useful. And the reason it's reasonable and useful is because it reflects a reasonable and useful distinction between data and metadata.
> What is an example of this distinction between attributes and elements which is not just syntax?
I don't understand that question.
My claim is that, in the context of markup languages, there is a useful distinction to be made between data and metadata, and that this distinction is useful enough that it is not unreasonable to make this distinction syntactically. Of course, it doesn't have to be made syntactically. In Lisp, there is no syntactic difference between function calls and control constructs. Consider:
(foo (baz bar) bing)
Is (bar bar) a function call? If FOO is a macro that expands to:
(dotimes (baz bar) bing)
then BAZ is a variable binding. Arguably, it would be worthwhile to make a syntactic distinction here. For example, you could use square brackets for variable bindings, so that you could tell that in:
(foo [baz bar] bing)
BAZ was a variable binding without having to know how FOO was defined. It's not a slam dunk, but it is a defensible position.
Likewise, it is a defensible position that the difference between <foo baz=bar>bing</foo> and <foo><baz>bar</baz></foo> -- whatever that difference might actually be in practice -- is valuable and ought to be preserved. Again, not a slam-dunk, but a defensible position.
What makes Erik clearly wrong is this his rendering of <foo baz=bar>bing</foo> is NOT actually any simpler than a rendering that preserves the attribute/element distinction. His rendering has EXACTLY the same level of nesting, the same number of tokens. The ONLY difference is the location of a paren. And the way he moves the paren, he loses information. Without a compelling argument why moving that paren has more value than the information that he loses, that paren ought not to be moved. All else being equal (and in this case all else is equal) it is better to keep information than to lose it. Not only does Erik not make a compelling argument, he makes no argument at all. He simply proclaims that it is "incredibly stupid" and his acolytes, for reasons passing my comprehension, agree.
You keep repeating that, but the more you discuss it, the less "clear" it is.
> I don't understand your question.
You acknowleded that we need to have a specification in order to make sense from a piece of markup. When we know what elements are to be expected in a format, what "clear" and "useful" advantage gives an additional arbitrary syntactic separatation over a sub-element-only layout? and why is it more "reasonnable" to have this separation when it actually make it slightly more difficult to manipulate the data?
> My claim is that, in the context of markup languages, there is a useful distinction to be made between data and metadata, ...
Originally, attributes made sense "in the context of markup languages" because attributes were metadata and sub-elements where "content". This is a reason why Naggum was first favorable for the distinction. But then the line was blurred, because not everything is so simple and you find attributes that refer to "data" (title attribute) and sub-elements that refer to "meta-data" (<meta> tag, for example).
> (foo [baz bar] bind) > ... you could tell that ... BAZ was a variable binding without having to know how FOO was defined. It's not a slam dunk, but it is a defensible position.
You don't need to know how FOO was defined, but you have a contract with FOO: there are many other distinctions one could make (not only bindings/parameters): will you invent a new syntax for everyone of them? Is that really useful? XML is used when you don't want to have a complex syntax and when a standard AST suffice. And then, attributes are an added complexity with little benefits.
It syntactically distinguishes information that applies to the tag from information to which the tag applies.
> why is it more "reasonnable" to have this separation when it actually make it slightly more difficult to manipulate the data?
It's a tradeoff, of course. Reasonable people can disagree about whether the tradeoff is worth it. But that's my point: reasonable people can disagree.
> But then the line was blurred
Any language feature can be abused. The proper response IMO is to stop abusing the feature, not to eliminate it.
> will you invent a new syntax for everyone of them?
I don't know. What other kinds of distinctions did you have in mind?
> attributes are an added complexity with little benefits
I understand that you believe this. Do you see how a reasonable person might disagree?
> Reasonable people can disagree about whether the tradeoff is worth it.
> But that's my point: reasonable people can disagree.
Sure, we disagree. I understand that you think there is a tradeoff, like in many design decisions. However, you did not tell me what benefits you expect from having the syntactical distinction.
> It syntactically distinguishes information that applies to the tag from information to which the tag applies.
That statement alone does not say why it is a good thing to distinguish syntactically both kind of informations. This looks interesting, of course, to be able to have a distinction. The fact that there is a distinction on the semantical level does not mean it should be there syntactically, though.
The syntax for attributes is unfortunately flawed, which is why ...
> Any language feature can be abused. The proper response IMO is to stop abusing the feature, not to eliminate it.
... is taking the problem completely backwards. No language feature were abused. In fact, attributes were acting against a natural organization of information. And that is why, as a workaround, it was needed to express meta-data with tags. I don't expect you to agree with this, so consider a classical example of markup usage.
You want to represent a document, with reviewers, publication dates and authors (those are meta-informations, right?) as well as content (the actual text being stored). However, there exists meta-informations about people (name, title) and dates (calendar). Where do we store structured meta-informations about attributes?
Unfortunately, attributes do not allow to express structured information, and they cannot have meta-informations attached to them. Here is what you obtain:
<root>
<document author="id0"
published_in="ACM"
publication_date="2010/03/02"
publication_volume=345
link="doi://1020301.202.301.1023"
reviewers_id="id1;id2;id3;id4">
... content ...
</document>
<peoples>
<people id="id0"><name>John Doe</name>...</people>
<people id="id1">...</people>
<people id="id2">...</people>
<people id="id3">...</people>
<people id="id4">...</people>
</peoples>
<root>
Notice how informations about publication are scattered into different attributes instead of being a single attributes with sub-components? (has the document been published in March or February? In which timezeone?)Authors are only indirectly referenced through identifiers, because the real structure cannot be easily expressed in attributes only. Also, a list of reviewers is actually a string with semicolon-separated identifiers.
An so, peoples are not just meta-informations, but tags with nested children and you must have a "root" element around your document, and a special list of "peoples". Just to be clear, having identifiers is not bad and could be a good way to model relationships. The problem is that you do not have a choice anymore of using different level of meta-attributes.
Notice how the link to a "DOI" identifier is itself encoded in a string (this is a custom format just for this example), instead of using a more useful nested structure:
(link (protocol doi)
(path (digits 1020301 202 301 1023)))
Each time you use a string to encode structured information in an attribute with a custom mini-language, you are asking for trouble.
Imagine how each of those strings now need to have a dedicated parser because you need to take care of escaping "special" characters.You might say that this is unfortunate that attributes are "flat", and that maybe a kind of hierarchical way of expressing attributes would be more preferable. And then, you would have nested-attributes as well as nested-elements. Why not merge them into the same syntactical structure?
If you consider that identifiers are not necessary, or if your format allows for sharing common sub-expressions (like #1=(author), #1#), then you could go with that kind of data-format:
(document (author (name "John Doe") (job-title "Professor") (institution "MIT"))
(anchor
(link (protocol doi)
(path (digits 1020301 202 301 1023)))
(target blank-page))
(reviewers (reviewer (name "..."))
(reviewer (name "..."))
...)
(encoding (utf 8))
(sections
...))
Then, you have multiple layers of "meta"-informations, instead of just 2: "data" and "dumb meta-data".
I agree we disagree, but I do not think both approaches are equal.
You talk about tradeoffs, but I really do not see anything useful in having attributes, whereby I can see the inconvenience they bring when trying to structure information in a meaningful way.That's because you chose examples that show attributes at their worst.
Suppose that instead of a document with a single author you instead had a document to which many people contributed, and you wanted to mark it up to show who wrote which section. Using attributes (and identifiers) you would have, e.g.
<author id=Bob>[info about Bob]</author>
<author id=Alice>[info about Alice]</author>
<span author=Bob>This part was written by Bob</span>
<span author=Alice>and this part was written by Alice</span>
<span author=Bob>and this part was written by Bob again.</span>
This example also highlights why it is sometimes NECESSARY to use identifiers in order to produce the semantically correct structure. Suppose you put all the author information in-line as you suggest. The result would look something like this: <span><author><name>Bob</name>[info about Bob]</author>This part was written by Bob</span>
<span><author><name>Alice</name>[info about Alice]</author>This part was written by Alice</span>
<span><author><name>Bob</name>[info about Bob]</author>This part was written by Bob</span>
Were the first and third parts written by the same person, or by two different people whose names both happen to be Bob? If you put everything in-line there is no way to express that two pieces of structure are intended to be EQ to each other.I already mentionned that with a Lisp like data-format, shared sub-expressions could be denoted using CL's reader variables:
(document
#1=(author (id "Bob") ... )
#2=(author (id "Alice") ... )
(span (author #1#) "written by Bob")
(span (author #2#) "written by Alice")
(span (author #1#) "written by Bob"))
I do not claim that this is the most appropriate solution in all cases, just that we are not forced to introduce indirection levels when unnecessary. Now, if I am using Lisp and I want to introduce external references to authors described in other documents, I could introduce a meta-data with an appropriate semantical structure: (external-element (pathname (directory (relative "path" "to"))
(type "lisp")
(name "file"))
(tree-path 2 1 3 2 2 3))
This would be a practical way to encode a precise location in a tree in an external file. And I could use this form everywhere I need to reference an object. Also, the tree-path notation is handy because there is no distinction between an attribute or an element, just which branch to take at each step from the root.Now, with XML attributes, I would typically have an "xref" attribute. How can we model xref attributes? If we wanted to have structured data, we would need to create external tags with the same concepts as above, like <pathname>, create a local identifier for each xref and refer indirectly to each xref using their local identifier: because we can only put strings. I mean:
<author xref="xref02">
...
<xref id="xref02">
<pathname> ... </pathname>
<tree-path> ... </tree-path>
</xref>
Or, we do as everybody and encode it like for XMI, or ECORE, or any other custom format, with a complex string, hoping that HTML entities are properly escaped.Besides, you failed to notice that you had <author> tags, which precisely goes against your idea that there should be a place for "meta-data" and a place for "data": effectively, authors are now part of the content of the document, and are not only meta-informations.
If you think my examples are artificial, open the source code of this page, and observe how any kind of complex information written in attributes has to be properly escaped to bypass the limitation of stringly-typed data:
reply?id=9556252&goto=item%3Fid%3D9555880"
href="vote?for=9556252&dir=up&auth=0UU000REDACTED000208d8b9f4a45575b4edea3779&goto=item%3Fid%3D9555880"
Notice how you need to escape HTML entities in inline javascript attributes (onclick) but not on script tags. Why are inline javascript not tags instead?(see http://stackoverflow.com/questions/8749001/escaping-html-ent...).
Whatever example you choose, you cannot deny the fact that attributes are not given the same rights as elements, because the way they do not allow to contain structured data or cannot have meta-attributes themselves.
I did read it.
> I already mentionned that with a Lisp like data-format, shared sub-expressions could be denoted using CL's reader variables:
Yes, of course this is possible. But that's just a different way of implementing tags (and not even a very good one either because your tags are constrained to be numeric).
> we are not forced to introduce indirection levels when unnecessary
That's a tautology.
> I could use this form everywhere I need to reference an object.
Of course you could. Most problems have more than one reasonable solution. But pointing out one reasonable solution is irrelevant to the question of whether a different solution is also reasonable.
> your idea that there should be a place for "meta-data" and a place for "data"
That wasn't exactly my idea. What I said was that there was value in having a syntactic distinction between data and meta-data. But I didn't say that this distinction should be universal. In fact it is impossible to distinguish between data and metadata in general, so you can always come up with examples where a particular datum's role is ambiguous. That doesn't change the fact that in many practical circumstances, having a syntactic distinction is appropriate and useful.
> observe how any kind of complex information written in attributes has to be properly escaped
Again, citing circumstances where things fall apart does not change the fact that in many practical circumstances, having a syntactic distinction between data and meta-data is appropriate and useful.
If you choose to reply to this, please remember: I'm a Lisp fan. (Look at my HN user ID!) I hate XML. I much prefer S expressions. When I have to deal with XML, the first thing I do is parse it into S-expressions. The world would be a better place if everything were S-exprs no one used SGML or any of its devil spawn syntaxes. But that's not the world we live in. In the world we live in, where markup languages exist and are required to have matching end tags, attributes are a defensible design.
You are correct that:
<foo bar="zot">quux</foo> => (foo (bar "zot"))
<foo><bar>zot</bar></foo> => (foo (bar "zot"))
Is an ambiguity. However in his <|> syntax: <foo bar="zot">quux</foo> => <foo <bar | "zot">>
<foo><bar>zot</bar></foo> => <foo | <bar | "zot">>
What about, say: <foo bar="zot">quux</foo>
as (foo (bar "zot") (data "quux"))
Or any other keyword which you could reserve as being the special "non-meta" data? (foo (bar "zot")) is then unambiguously <foo bar="zot"/>
(foo (data (bar "zot"))) is then <foo><bar>zot</bar></foo>
I'm not sure whose side I'm on by proposing this. I'd be interested to know."Whether something is an attribute or element is _completely_ arbitrary."
THAT is the point on which he is (IMHO) clearly wrong. (He's wrong about a bunch of other things too, but that's the most serious mistake.)
EDIT: Here is Erik doubling down on his position:
"I have a simple way to get rid of the annoying verbosity of these stupid languages while _retaining_ that mistake [sic] between attribute values and elements"
He does not appear to make an argument as to why he believes this, so I'd say his claim is at worst unsubstantiated.
I find it hard to believe that there's a objectively correct decision about the number of semantic concepts that "should" be encoded in a syntax, but I can understand why lisp enthusiasts would be on the 'closer-to-none end of that spectrum.
I'd be interested to hear why you think it's so essential. The only argument I'm really aware of is compatibility with existing markup languages.
I would guess that a markup syntax that is as simple and regular (ie. syntactically consistent) as possible would be the easiest to operate on algorithmically. I would also guess that this would make it easier to build, on top of this language, tools which present the content in various ways that are easier to read/write/manually-manipulate if you so desired.
Actually, his example syntax makes this argument implicitly. He is suggesting that his tools are significantly easier to implement by working with plain S-Expressions, and that they can easily be mapped to a 'write-friendly markup language that is isomorphic to XML anyway.
I make no claims about the quality of his presentation or the clarity of his arguments.
Really enjoy these types of articles on markup languages. If there are any other markup language nerds out there I've been chipping away at a simple one (https://github.com/breck7/space), and would love feedback. And if you have one as well always love looking at different ideas.
http://pkg-build.racket-lang.org/doc/pollen/
practicaltypography.com was made with it.
Simple: parse
<foo bar="zot">quux</foo>
as (JSON-like) {
"foo": {
"bar" : "zot",
"" : "quux"
}
}
Problem solved, XML is now logical again. <foo bar="zot">quux</foo>
would be represented as /foo/@bar=zot
/foo=quux
I think data serialization formats of this particular kind are underused. They are dead simple to parse while still being reasonably human-friendly (more so than XML, I'd say). Get rid of the attributes and introduce the convention that nodes with children named "0", "1", ... , "$N" are arrays and you can represent JSON.<foo bar="zot"><baz>quux</baz></foo>
[foo]
@bar="zoot"
[baz]
"quux"
[]
[]
I figured you would save a little in the serialization. In practice I rarely need such a thing, and just serialize a structure to whatever I'm working with (s expressions, or in java xstream etc since those xml files are read somewhere...)That said, the JSON representation has a bug: what if there are multiple child elements? A fix would be using numeric indices for the children rather than the empty string. Then it would look both like an object with keys (attributes) and an array (of elements). Though, if you want to serialize that back into XML, you would need to make sure you never use non-strings as attribute values! Another bug is that the objects don't maintain their tag name; writing code to process data in this representation would be fairly annoying because a pointer to an element would be an object plus a key, rather than just an object. A fix for this would be to have a "tag" key inside the object.