How are attributes parsed in Boost.PropertyTree? - c++

Say I have this XML format:
<Widget type="SomeWidget" name="foo">
<Event name="onmouseover">
dostuff();
</Event>
</Widget>
How do I read the attributes using Boost.PropertyTree?

If xml has such content:
<mode fullscreen="true">mode xxx</mode>
Use boost::property code:
get<string>("mode.<xmlattr>.fullscreen")
Oh yeah, it's ugly!

If your problem is to get attributes:
The attributes of an XML element are
stored in the subkey . There
is one child node per attribute in the
attribute node. Existence of the
node is not guaranteed or
necessary when there are no
attributes.
From the doc http://www.boost.org/doc/libs/1_44_0/doc/html/boost_propertytree/parsers.html#boost_propertytree.parsers.xml_parser
So just get them from the <xmlattr> key in the path.

Related

How to remove Qt layout from between two other layouts in Qt Creator's UI designer?

I have the following structure in my Qt form:
How can I completely remove the VerticalLayout_1, so that the gridLayout_8 will became an immediate and only child of page_4?
I tried selecting delete from the right click menu, but that deletes the childs of VerticalLayout_1 also. I also tried moving the gridLayout_8 in the drag and drop interface, but since it was the only child of the verticalLayout_1, I just wasn't able to move it to be in page_4.
One possible way would be to edit the .ui XML file manually to remove the unneeded layout. If you open up your XML file in an editor, you should find something like this:
...
<layout class="QGridLayout" name="page_4">
<item row="0" column="0">
<!-- below is the layout you want to remove -->
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<layout class="QGridLayout" name="gridLayout_8">
...
</layout>
</item>
</layout>
</item>
</layout>
...
In your case, you just need to remove the <layout> tag and its <item> child, so that the gridLayout_8 becomes a direct child of an <item> of page_4, i.e.:
...
<layout class="QGridLayout" name="page_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_8">
...
</layout>
</item>
</layout>
...
After that, you can re-open the XML file in QtCreator to make sure everything looks the way it should.
I am not sure if there is a simpler way to achieve the same result from QtCreator. If you know of any, feel free to add an answer.
It can be tricky to select, but in the form, you should've been able to select the gridLayout_8 as a unit and drag it into the page_4 layout. That would leave the verticalLayout_1 still present, but empty, and then you can easily delete it. If the gridLayout_8 layout has zero margins, then it might be impossible to select; you would have to set the margins to something so that the border of gridLayout_8 is separated from the border of verticalLayout_1.
I drag layouts around all the time. The hard part is making the sure the layout is selected rather than something inside it. Just be prepared to undo and try again if you drop in the wrong place or grab the wrong thing.

XSLT copy from external document

In XSLT 2.0 I am transforming a tei-xml document into HTML. In that transformationI need content from another document: I want to copy/transform a small set of nodes from the second document into the HTML output.
While processing the principal tei document I get the id and assign it to a variable:
<xsl:variable name="licenseid" select="./replace(#corresp,'#','')"/>
Then I go out to the other document and fetch the node using the variable, with the returned node assigned to a variable:
<xsl:variable name="licenseloc" select="doc(concat($somepath,'includes_sourcedesc.xml'))//tei:list[#type='copyright_type']/tei:item[#xml:id=$licenseid]"/>
This node I obtain looks like this:
<list type="copyright_type">
<item xml:id="copyright-cc-by-nc-sa-4.0">
<desc xml:lang="en">This work is made by available the author under the
<ref target="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International License</ref>.</desc>
</item>
</list>
And I want to transform it (from desc) to this:
<span>This work is made by available by the author under the
<a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International License</a>.</span>
If this were in my 'current' tei document I would handle it through templates, but I'm unsure how to copy and transform the nested layers from within a different 'current' document.

xmlserializer deserialize list containing attributes

I have xml that part of structure looks like this:
<IDList>
<ValuesList ID="1">
<Value>1</Value>
<Value>2</Value>
<Value>3</Value>
</ValuesList>
<ValuesList ID="2">
<Value>1</Value>
<Value>2</Value>
<Value>3</Value>
</ValuesList>
</IDList>
What should be model classes for xmlserializer, so I could deserialize it properly?
On the level of IDList it's quite easy:
[XmlArray("IDList")]
[XmlArrayItem("ValuesList")]
public List<CValuesList> idList = new List<CValuesList>();
but how can I do it when the array element has extra xml attribute?
I tried to do ot in the way shown here:
http://www.codemeit.com/xml/c-xmlserializer-add-an-attribute-to-an-array-element.html
but it didn't worked for me. The elements of the array haven't been deserialized.
There is no simple way to do that.
A good solution would be to create an object that contains a list and your properties and inherit/implements IXmlSerializable.
I've seen some kind of quick and dirty way on this site: http://funcakes.posterous.com/adding-elements-to-lists-in-the-xmlserializer. Since the object doesn't inherit from ISerializable, it won't be serialized as a list by the serializer.

XSLT counting elements with a given value

I need to count the number of elements in an XML file that have a particular value (to verify uniqueness). The XML file looks like this:
EDIT: I updated the original "simplified" XML with the actual hairy mess someone designed. Unfortunately, this is going to make all the previous Answers really confusing and wrong unless edited.
<root>
<ac>
<Properties>
<Property Name="Alive">
<Properties>
<Property Name="ID">
<Properties>
<Property Name="Value">
<long>11007</long>
</Property>
</Properties>
</Property>
</Properties>
</Property>
<Property Name="Dead">
<Properties>
<Property Name="ID">
<Properties>
<Property Name="Value">
<long>11008</long>
</Property>
</Properties>
</Property>
</Properties>
</Property>
...
<Property Name="MostlyDeadAllDay">
<Properties>
<Property Name="ID">
<Properties>
<Property Name="Value">
<long>99001</long>
</Property>
</Properties>
</Property>
</Properties>
</Property>
</Properties>
</ac>
</root>
I am trying to define a variable to see how many of the properties at the Alive/Dead level have the long value (ID) as defined in a template parameter. Something along these lines (though I suspect this is wrong)...
<xsl:param name="parPropId"/>
<xsl:variable name="countProperties">
<xsl:value-of select="count(/root/ac/
Properties/Property/
Properties/Property[#Name = 'ID']/
Properites/Property[#Name = 'Value']/long = $parPropId)"/>
</xsl:variable>
There can be multiple Property elements defined at the "ID" level. But I am fairly certain I can count on just one Property element ("Value") under "ID", and only one "long" element under "Value".
[disclaimer] Whoever designed the overall XML file I'm stuck working with REALLY didn't know how to structure XML (e.g., backwards use of attributes versus elements). I fear my XSLT thinking has temporarily been warped :) as a result. [/disclaimer]
This XPath:
count(//Property[long = '11007'])
returns the same value as:
count(//Property/long[text() = '11007'])
...except that the first counts Property nodes that match the criterion and the second counts long child nodes that match the criterion.
As per your comment and reading your question a couple of times, I believe that you want to find uniqueness based on a combination of criteria. Therefore, in actuality, I think you are actually checking multiple conditions. The following would work as well:
count(//Property[#Name = 'Alive'][long = '11007'])
because it means the same thing as:
count(//Property[#Name = 'Alive' and long = '11007'])
Of course, you would substitute the values for parameters in your template. The above code only illustrates the point.
EDIT (after question edit)
You were quite right about the XML being horrible. In fact, this is a downright CodingHorror candidate! I had to keep recounting to keep track of the "Property" node I was on presently. I feel your pain!
Here you go:
count(/root/ac/Properties/Property[Properties/Property/Properties/Property/long = $parPropId])
Note that I have removed all the other checks (for ID and Value). They appear not to be required since you are able to arrive at the relevant node using the hierarchy in the XML. Also, you already mentioned that the check for uniqueness is based only on the contents of the long element.
Your xpath is just a little off:
count(//Property/long[text()=$parPropId])
Edit: Cerebrus quite rightly points out that the code in your OP (using the implicit value of a node) is absolutely fine for your purposes. In fact, since it's quite likely you want to work with the "Property" node rather than the "long" node, it's probably superior to ask for //Property[long=$parPropId] than the text() xpath, though you could make a case for the latter on readability grounds.
What can I say, I'm a bit tired today :)
<xsl:variable name="count" select="count(/Property/long = $parPropId)"/>
Un-tested but I think that should work. I'm assuming the Property nodes are direct children of the root node and therefor taking out your descendant selector for peformance

MSXML Select Nodes Not Working

I am working on an automated testing app, and am currently in the process of writing a function that compares values between two XML files that should be identical, but may not be. Here is a sample of the XML I'm trying to process:
<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.**.com/**">
<subreport name="RBDReport">
<record rowNumber="1">
<field name="Time">
<value>0</value>
</field>
<field name="Reliability">
<value>1.000000</value>
</field>
<field name="Unreliability">
<value>0.000000</value>
</field>
<field name="Availability">
<value> </value>
</field>
<field name="Unavailability">
<value> </value>
</field>
<field name="Failure Rate">
<value>N/A</value>
</field>
<field name="Number of Failures">
<value> </value>
</field>
<field name="Total Downtime">
<value> </value>
</field>
</record>
(Note there may be multiple <subreport> elements and within those, multiple <record> elements.)
What I'd like is to extract the <value> tags of two documents and then compare their values. That part I know how to do. The problem is the extraction itself.
Since I'm stuck in C++, I'm using MSXML, and have written a wrapper to allow my app to abstract away the actual XML manipulation, in case I ever decide to change my data format.
That wrapper, CSimpleXMLParser, loads an XML document and sets its "top record" to the document element of the XML document. (CRecord being an abstract class with CXMLRecord one of its subclasses, and which gives access to child records singularly or by group, and also allowing access to the "value" of the Record (values for child elements or attributes, in the case of CXMLRecord.) A CXMLRecord contains an MSXML::MSXMLDOMNodePtr and a pointer to an instance of a CSimpleXMLParser.) The wrapper also contains utility functions for returning children, which the CXMLRecord uses to return its child records.
In my code, I do the following (trying to return all <subreport> nodes just to see if it works):
CSimpleXMLParser parserReportData;
parserReportData.OpenXMLDocument(strPathToXML);
bool bGetChildrenSuccess = parserReportData.GetFirstRecord()->GetChildRecords(listpChildren, _T("subreport"));
This is always returning false. The meat of the implementation of CXMLRecord::GetChildRecords() is basically
MSXML2::IXMLDOMNodeListPtr pListChildren = m_pParser->SelectNodes(strPath, m_pXMLNode);
if (pListChildren->Getlength() == 0)
{
return false;
}
for (long l = 0; l < pListChildren->Getlength(); ++l)
{
listRecords.push_back(new CXMLRecord(pListChildren->Getitem(l), m_pParser));
}
return true;
And CSimpleXMLParser::SelectNodes() is:
MSXML2::IXMLDOMNodeListPtr CSimpleXMLParser::SelectNodes(LPCTSTR strXPathFilter, MSXML2::IXMLDOMNodePtr pXMLNode)
{
return pXMLNode->selectNodes(_bstr_t(strXPathFilter));
}
When run, the top record is definitely being set to the <report> element properly. I can do all sorts of things with it, like getting its child nodes (through the MSXML interface, not through my wrapper) or its name, etc. I know that my wrapper can work, because I use it elsewhere in the app for parsing an XML configuration file, and that works flawlessly.
I thought maybe I was doing something faulty with the XPath query expression, but every permutation I could think of gives no joy. The MSXML::IXMLDOMNodeListPtr returned by IXMLDOMNodePtr::SelectNodes() is always of length 0 when I try to deal with this XML file.
This is driving me crazy.
I'm used to doing this with .NET's XmlDocument objects, but I think the effect is the same here:
If the XML document includes a namespace -- even an unnamed one -- then the Xpath query has to use one as well. So, you'll have to add the namespace to the XMLDoument which you might as well give a name in the code, and the include the prefix in the XPATH query (it doesn't matter that the prefixes are different between the xml document and the xpath, as long as the namespaces sort it out)
SO, while you are using an XPath like /report/subreport/record/field/value, you actually need to first set the namespace of your document:
pXMLDoc->setProperty(_bstr_t("SelectionNamespaces"),
_bstr_t("xmlns:r="http://www.**.com/**"));
and then selectNodes() using /r:report/r:subreport/r:record/r:field/r:value
I see no reference to a namespace when you're selecting nodes. I'd expect this to be the fundamental problem.