ValueTree: Why U No <Tag>text</Tag>


#1

What’s the reasoning for not having the ValueTree class be able to load XML that has text tags like

<node>
    <tag>tagText</tag>
</node>

Appropriate followup:
is there an easy way to replace a tag like in an XML tree shown above with an attribute equivalent?
e.g. convert the above to:

<node tag="tagText"/>

#2

ValueTree was never intended to be a 1:1 mapping for XML. It’s a subset.

I designed its structure so that you can go ValueTree->XML->ValueTree without loss of data (to make it easy to store a ValueTree), but the XML->ValueTree converter was only designed to load XML that came from a ValueTree, not arbitrary XML data from other sources.

The class could be extended to handle text tags, but that’d involve adding extra baggage to handle it as a special case. And given that lots of people have been using ValueTrees intensively for many years and this has never been requested before, I guess the demand for it is low!

Converting the XML as a step before converting it to a ValueTree is easy enough - you’d just scan through the XmlElements for text nodes and move them into attributes. It’d be a pretty quick operation.

Bear in mind though that if you need to round-trip this document and convert them back to text nodes after modifying it, you’ll need to be a bit smarter than just turning them into attributes - you’d probably want to convert them into normal XML tag nodes with a special name, to retain the overall structure.


#3

thanks. I came up with this. maybe it will help someone trying to convert text nodes to attributes:

void MainContentComponent::treeChildSwap(juce::XmlElement *tree, int indentation)
{
    if( tree == nullptr ) { return; }

    for (juce::XmlElement* child = (*tree).getFirstChildElement();
         child != nullptr;
         child = child->getNextElement())
    {
        if( child->isTextElement() )
        {
            /*
             you're on a node like this:
            <sbxqw>someText</sbxqw>

             convert it to
            <sbxqw value="someText"/>

             tree is the <sbxqw/>
             child is <unnamed>someText</unnamed>
             */
            tree->setAttribute("value", child->getText());
            tree->removeChildElement(child, true);
            child = tree->getFirstChildElement(); //pruned a child, reset child to start of tree and start loop over. 
            if( child == nullptr) { return; }
        }
        else if( child->getNumChildElements() > 0 )
        {
            treeChildSwap(child, indentation + 1);
        }
    }
}

for input data like this:

<node>
  <gfndf>
    <licji>randomString</licji>
    <abmld value="lybuw"/>
    <qskws value="elfql"/>
    <rmncm>randomString</rmncm>
    <fhntw>
      <hnypg>randomString</hnypg>
    </fhntw>
    <kvgql>
      <etney value="rwnek"/>
    </kvgql>
  </gfndf>
  <ycmyo>
    <hvewn>randomString</hvewn>
    <lipqn>randomString</lipqn>
    <fvdje value="ptwvd"/>
    <bngwt>randomString</bngwt>
    <lwrjo>
      <ubbsv value="rwlla"/>
      <gjviy>randomString</gjviy>
      <noixm>randomString</noixm>
    </lwrjo>
    <xgall>
      <oadws value="ewkhr"/>
      <tgwwj>randomString</tgwwj>
      <mocis>randomString</mocis>
    </xgall>
  </ycmyo>
  <yqyid>
    <vrvig value="mbvcs"/>
    <cwjvx value="ttbky"/>
    <fvsph>
      <xdwyv value="fcimv"/>
      <ppcfk>randomString</ppcfk>
    </fvsph>
    <tjrbc>
      <briwk>randomString</briwk>
    </tjrbc>
  </yqyid>
</node>

it converts it to this:

<?xml version="1.0" encoding="UTF-8"?>

<node>
  <gfndf>
    <licji value="randomString"/>
    <abmld value="lybuw"/>
    <qskws value="elfql"/>
    <rmncm value="randomString"/>
    <fhntw>
      <hnypg value="randomString"/>
    </fhntw>
    <kvgql>
      <etney value="rwnek"/>
    </kvgql>
  </gfndf>
  <ycmyo>
    <hvewn value="randomString"/>
    <lipqn value="randomString"/>
    <fvdje value="ptwvd"/>
    <bngwt value="randomString"/>
    <lwrjo>
      <ubbsv value="rwlla"/>
      <gjviy value="randomString"/>
      <noixm value="randomString"/>
    </lwrjo>
    <xgall>
      <oadws value="ewkhr"/>
      <tgwwj value="randomString"/>
      <mocis value="randomString"/>
    </xgall>
  </ycmyo>
  <yqyid>
    <vrvig value="mbvcs"/>
    <cwjvx value="ttbky"/>
    <fvsph>
      <xdwyv value="fcimv"/>
      <ppcfk value="randomString"/>
    </fvsph>
    <tjrbc>
      <briwk value="randomString"/>
    </tjrbc>
  </yqyid>
</node>

#4

Question for ya, @jules. The valueTree class is not obviously meant to be a 1:1 mapping of the XmlElement class, but it might as well be as I’d bet that’s how a lot of folks end up using it, with the exclusion of Text “attributes”. What was the reasoning behind having valueTree use set/getProperty and XmlElement use set/getAttribute? it seems to me that the difference in function name for 2 classes that essentially are built around the same data model (an XML tree) adds to the confusion of using ValueTree, especially if the ValueTree is created from XML and you (the user of the class) are staring at the xml file reading the attributes, trying to figure out how to access them in your ValueTree class.

So, why not just have the two classes use the same terminology (set/getAttribute) to aid in understanding how to use ValueTree to represent your XML data (that doesn’t have <xyz>text</xyz>, of course)?