I've been looking for hours a solution to my (simple ?) problem but I cannot find anyone who encountered this. I'm using latest version of rapidxml(1.13).
I'm currently trying to create a tile-based engine and I need to read tmx file.
I'm been using rapidxml for a while and so far everything was great. It was able to read every node perfectly and with an expected behavior. But I came across one node it has a problem with.
This is my tmx file :
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.6.0" orientation="orthogonal" renderorder="right-down" width="100" height="100" tilewidth="32" tileheight="32" infinite="0" nextlayerid="12" nextobjectid="1">
<tileset firstgid="1" source="../../../Tile_engine/Tile_engine/sprite/[Base]BaseChip_pipo.tsx"/>
<tileset firstgid="1065" source="../../../Tile_engine/Tile_engine/sprite/collision.tsx"/>
<layer id="4" name="background" width="100" height="100">
<properties>
<property name="bg" type="bool" value="false"/>
</properties>
<data encoding="csv">
//I've removed the data for clearer view
</data>
</layer>
<layer id="6" name="object" width="100" height="100">
<properties>
<property name="isSolid" type="bool" value="true"/>
</properties>
<data encoding="csv">
//I've removed the data for clearer view
</data>
</layer>
<layer id="9" name="front" width="100" height="100">
<properties>
<property name="isSolid" type="bool" value="false"/>
</properties>
<data encoding="csv">
//I've removed the data for clearer view
</data>
</layer>
<layer id="11" name="collision" width="100" height="100">
<data encoding="csv">
//I've removed the data for clearer view
</data>
</layer>
</map>
In order to debug, I'm using a basic read with rapidxml :
xml_document<> doc;
xml_node<> * root_node;
// Read the xml file into a vector
ifstream theFile ("sprites/map_wtf.tmx");
vector<char> buffer((istreambuf_iterator<char>(theFile)), istreambuf_iterator<char>());
buffer.push_back('\0');
// Parse the buffer using the xml file parsing library into doc
doc.parse<0>(&buffer[0]);
// Find our root node
root_node = doc.first_node("map");
When I try to read (and count) the layer node for example :
int count_node(0);
for(xml_node<> * child = root_node->first_node("layer"); child != nullptr; child = child->next_sibling())
count_node++;
cout << count_node;
The output is correct and gives me 4.
But when I try to read the tileset node, the output gives me 6.
So I've assumed the behavior is link to the /> at the end of the tileset node (<tileset firstgid="1" source="../../../Tile_engine/Tile_engine/sprite/[Base]BaseChip_pipo.tsx"/>).
Since the nested property node has the same pattern (<property name="bg" type="bool" value="false"/>), I've tried this code :
int count_node(0);
for(xml_node<> * child = root_node->first_node("layer")->first_node("properties")->first_node("property"); child != nullptr; child = child->next_sibling())
count_node++;
cout << count_node;
who gives me the correct output aka : 1.
I've tried different parsing options for the line doc.parse<0>(&buffer[0]) but nothing works. I've also read the content of the buffer during theses tests and it was correct.
I must have the wrong way to read the file but I cannot understand why this script reads layer node and property node fine, but not the tileset ones.
Can anyone help me ?
Thanks !
The question is based on a misunderstanding about the result of
xml_node<> * child = root_node->first_node("layer");
child = child->next_sibling();
The child = child->next_sibling() returns the next node on the same level irregardless of the node name or any other constraint that was applied during the root_node->first_node("layer") selection.
However, the next_sibling signature is basically the same as the first_node signature, so it can be used to apply criteria to the next sibling node to be found.
So the (untested) approach would be like
int count_node(0);
for(xml_node<> * child = root_node->first_node("tileset"); child != nullptr; child = child->next_sibling("tileset"))
count_node++;
cout << count_node;
Related
I have an XML file below where I need to get the text inside of the <Description> tag under the <Checklist> tag where the <Sequence> tag has the text 40. How to achieve it?
<?xml version="1.0" encoding="UTF-8"?>
<SyncMaintenanceOrder>
<DataArea>
<MaintenanceOrder>
<MaintenanceOrderHeader>
<DocumentID>
<ID accountingEntity="AT">1105442</ID>
</DocumentID>
<Description>Routine Bridge Inspection - S6</Description>
<PriorityCode>2</PriorityCode>
<ReportedDateTime>2020-04-29T20:21:27Z</ReportedDateTime>
</MaintenanceOrderHeader>
<MaintenanceOrderLine>
<LineNumber>10</LineNumber>
<RemainingDuration>PT8H0M0S</RemainingDuration>
<ActivityDeferredIndicator>false</ActivityDeferredIndicator>
<UserArea>
<EamCheckListInfo>
<CheckList>
<CheckListItem>
<Sequence>40</Sequence>
<Description>Half joints (Superstructure elements)</Description>
</CheckListItem>
<CheckListItem>
<Sequence>160</Sequence>
<Description>Substructure drainage (Durability elements)</Description>
</CheckListItem>
<CheckListItem>
<Sequence>60</Sequence>
<Description>Parapet beam or cantilever (Superstructure elements)</Description>
</CheckListItem>
</CheckList>
</EamCheckListInfo>
</UserArea>
</MaintenanceOrderLine>
</MaintenanceOrder>
</DataArea>
</SyncMaintenanceOrder>
I need sample of an XSLT code for selecting only the text node described above.
I'm not sure I really get your question.
This will print the Description of the CheckListItem which has a Sequence of 40:
<xsl:value-of select="//CheckListItem/Sequence[text()='40']/../Description"/>
Try it here: https://xsltfiddle.liberty-development.net/ehVZvvZ
Try the below code
<xsl:value-of select="*[local-name(.)='SyncMaintenanceOrder']/*[local-name(.)='DataArea']/*[local-name(.)='MaintenanceOrder']/*[local-name(.)='MaintenanceOrderLine']/*[local-name(.)='UserArea']/*[local-name(.)='EamCheckListInfo']/*[local-name(.)='CheckList']/*[local-name(.)='CheckListItem']/*[local-name(.)='Sequence'][text() = '40']/../*[local-name(.)='Description']" />
I just want to know, is there any way to iterate a List and print it's content one by one (incremental) in each groupFooter?
I create a group in my report, and in each groupFooter section, I want to display content from a java.util.List I sent from Java class via parameter.
Currently I just using jr:list and jr:listContents in my groupFooter, and the result is all contents from the list is printed in every groupFooter. I got an headache to solve this, so any help will relief me.
I don't think you should try to iterate the List to get content in a certain number of groupFooter, instead I would get content directly List based on index.
What we need is simple a pointer (position in list), in your case this number seems to be an incremented number every time we have a new group.
A variabile counting as group change is:
<variable name="countMyGroup" class="java.lang.Integer" incrementType="Group" incrementGroup="Group1" calculation="Count">
<variableExpression><![CDATA[""]]></variableExpression>
<initialValueExpression><![CDATA[0]]></initialValueExpression>
</variable>
With this simple variabile we will now have the current number of group that is displayed and we can add a textField with the value from or List using this number. see java.util.List.get(int index)
<parameter name="listOfStuff" class="java.util.List" isForPrompting="false"/>
.....
<textField>
<reportElement x="120" y="0" width="267" height="17" uuid="b45699d3-5d34-4d88-b7bc-2666cf787ace">
<printWhenExpression><![CDATA[$P{listOfStuff}.size()>=$V{countMyGroup}]]></printWhenExpression>
</reportElement>
<textFieldExpression><![CDATA[$P{listOfStuff}.get($V{countMyGroup}-1)]]></textFieldExpression>
</textField>
Note: the printWhenExpression will avoid IndexOutOfBoundsException, hence that the group number is higher then the size of our List
Full jrxml example, it use a dummy group changing on each record, to try it use a JREmptyDatasource with a couple of records.
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="ListOnEachPage" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="33394f25-66fc-431b-ac82-88660e9115e5">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="Empty 4 records"/>
<parameter name="listOfStuff" class="java.util.List" isForPrompting="false">
<defaultValueExpression><![CDATA[Arrays.asList(new String[]{"group 1","group 2","group 3"})]]></defaultValueExpression>
</parameter>
<queryString>
<![CDATA[]]>
</queryString>
<variable name="countMyGroup" class="java.lang.Integer" incrementType="Group" incrementGroup="Group1" calculation="Count">
<variableExpression><![CDATA[""]]></variableExpression>
<initialValueExpression><![CDATA[0]]></initialValueExpression>
</variable>
<group name="Group1">
<groupExpression><![CDATA[$V{REPORT_COUNT}]]></groupExpression>
<groupFooter>
<band height="34">
<textField>
<reportElement x="120" y="0" width="267" height="17" uuid="b45699d3-5d34-4d88-b7bc-2666cf787ace">
<printWhenExpression><![CDATA[$P{listOfStuff}.size()>=$V{countMyGroup}]]></printWhenExpression>
</reportElement>
<textFieldExpression><![CDATA[$P{listOfStuff}.get($V{countMyGroup}-1)]]></textFieldExpression>
</textField>
<textField>
<reportElement x="445" y="0" width="100" height="17" uuid="e5c46332-b137-4c55-99e4-265c87b8f97d"/>
<textFieldExpression><![CDATA[$V{countMyGroup}]]></textFieldExpression>
</textField>
</band>
</groupFooter>
</group>
<detail>
<band height="63" splitType="Stretch">
<staticText>
<reportElement x="140" y="20" width="264" height="30" uuid="1ec9f950-dd2d-4c18-a81a-b0da937eb1b5"/>
<textElement>
<font size="14"/>
</textElement>
<text><![CDATA[Just some text to simulate detail band]]></text>
</staticText>
</band>
</detail>
</jasperReport>
Output, see how values from list are extracted as long as we are within size of List
You need to make a variable which increment at your group level.
Step 2 its to use that variable in a simple textfield or what component you want (not a collection component) and put his expression like this : list.indexOf(countVariable)
I am just starting to use TinyXML2 so I am probably doing something wrong. Anyway:
tinyxml2::XMLDocument txDoc;
tinyxml2::XMLElement *rootnode;
XMLError err = txDoc.LoadFile(xmlFile.c_str()); // err says no error.
rootnode = txDoc.FirstChildElement("common");
rootnode is still set to a null pointer after the final line. I assume this is because it cannot find "common".
Here is my XML (shortened):
<?xml version="1.0"?>
<font>
<info outline="0" spacing="1,1" padding="0,0,0,0" aa="1" smooth="1" stretchH="100" unicode="1" charset="" italic="0" bold="0" size="16" face="Arial"/>
<common blueChnl="0" greenChnl="0" redChnl="0" alphaChnl="1" packed="0" pages="1" scaleH="128" scaleW="256" base="13" lineHeight="16"/>
<pages>
<page file="Font_Arial_16_0.png" id="0"/>
</pages>
<chars count="191">
... (removed additional <char>'s)
<char id="32" chnl="15" page="0" xadvance="4" yoffset="0" xoffset="0" height="16" width="1" y="85" x="121"/>
... (removed additional <char>'s)
</chars>
<kernings count="70">
... (removed additional <kerning>'s)
<kerning amount="-1" second="65" first="32"/>
... (removed additional <kerning>'s)
</kernings>
</font>
However, in the XMLDocument txDoc, the charBuffer only contains:
<?xml version="1.0"?>
<font
And apparently nothing more. So I assume it says there is no error because it finds and opens the file, but doesn't seem to get everything that's inside it.
Does anyone have any ideas? I am using TinyXML2, not 1.
I get the impression I am navigating the file incorrectly.
For the XMLDocument, FirstChildElement() is equivalent to RootElement() and your root element here is font. You want to call FirstChildElement() of the root element.
It's confusing. My program was working reliably. Then, I did some changes in a hurry, they didn't work, re-winded them, went to show my program and it no longer works. My fault for not making new copy every 10min. The thing is however, the program crashes in a place which makes no sense.
QDomElement Expense::toNode()
{
QDomElement e=Entry::toNode(); //Entry is parent of Expense
QString temp;
//std::string getThis=e.nodeName().toStdString();
temp=QString::fromStdString(Category); //Category is string field
//e.hasAttribute("category"); //this works
//e.setAttribute("ha","hi"); //this crashes program
//e.setAttribute("category",temp); //this also crashes program
return e;
}
I thought that maybe in hurry I modified some library, but if I create a new QDomElement, and edit it's attributes, there is no problem at all. Then I thought that maybe my node is not a node at all, but I can use many other functions (like for example e.hasAttribute). Is there limit to amount of attributes we can set? What might be the error?
In case it helps:
QDomElement Entry::toNode()
{
QDomDocument d("EzXpns");
QDomElement e=d.createElement("entry");
QString temp;
temp=QString::fromStdString(Name);
e.setAttribute("name",temp);
temp=QString::fromStdString(to_string(static_cast<long double>(Amount)));
e.setAttribute("amount",temp);
temp=QString::fromStdString(to_string(static_cast<long long>(Date[0])));
e.setAttribute("dateyear",temp);
temp=QString::fromStdString(to_string(static_cast<long long>(Date[1])));
e.setAttribute("datemonth",temp);
temp=QString::fromStdString(to_string(static_cast<long long>(Date[2])));
e.setAttribute("dateday",temp);
temp=QString::fromStdString(Comment);
e.setAttribute("comment",temp);
return e;
}
Edit: I should have specified, that if I try to debug this is the message I get:
TestBuild.exe has triggered a breakpoint
then
Unhandled exception at 0x77d415de in TestBuild.exe: 0xC0000005: Access violation reading location 0x13fb8ff8.
then
0x77d3016e in TestBuild.exe: 0x00000000: The operation completed successfully.
Edit2: Sample xml
<!DOCTYPE data>
<EzXpns>
<account>
<login name="b" password="1"/>
<expHis>
<entry comment="9" dateday="1" name="k" dateyear="0" amount="9" datemonth="1"/>
<entry comment="9" dateday="1" name="b" dateyear="0" amount="9" datemonth="1"/>
<entry comment="9" dateday="1" name="b" dateyear="0" amount="9" datemonth="1"/>
<entry comment="9" dateday="1" name="b" dateyear="0" amount="9" datemonth="1"/>
<entry comment="9" dateday="1" name="b" dateyear="0" amount="9" datemonth="1"/>
</expHis>
<incomeHis/>
</account>
</EzXpns>
Solution was within the Qt documentation.
Look at how I create new element, I do it by calling QDomDocument d("EzXpns"); , which is a mistake. In Qt, after the QDomDocument is destroyed SO ARE ALL CHILD NODES. It worked before just because of pure luck. Creating one QDomDocument, and then passing it around, solved my problem.
I have created non-binary tree in order to load xml data in it and be used later for dialogue system.I want to implement the dialogue systems like in fallout where every answer can contain 4 different nodes with another answers.So far i created xml with the sentences
<Dialogue>
<Node>Hello,what do you want?</Node>
<Leaf>Nothing</Leaf>
<Leaf>Really?</Leaf>
<Branch>
<Node>Really?</Node>
<Leaf>Yes></Leaf>
<Branch>
<Node>No</Node>
<Leaf>Why not?</Leaf>
</Branch>
</Branch>
</Dialogue>
here node in the tree in c++ is represented as parent Leafs are child and below first branch node is child of the upper node.I find difficultis to load the xml data in tree with this structure so do you have ideas for better structures?
With your current structure of XML, you'll find it tricky to implement this, I'll suggest one option..
<Dialogue>
<Node id="root">
<Prompt>Hello,what do you want?</Prompt>
<Response>
<match>Nothing</match>
<Branch node_id="nothing"/>
</Response>
: <!-- more Response nodes -->
</Node>
<Node id="nothing">
<Prompt>Really?</Prompt>
<Response>
<match>Yes</match>
<Branch node_id="nothing.yes"/>
</Response>
<Response>
<match>Actually...</match>
<Branch node_id="nothing.actually"/>
</Response>
</Node>
<Node id="nothing.yes">
<Prompt>Why not?</Prompt>
: <!-- Response Nodes -->
</Node>
<Node id="nothing.actually">
<Prompt>Okay, what then?</Prompt>
: <!-- Response Nodes -->
</Node>
</Dialogue>
In reality, with this type of data, you need a map to store each "Node", where a Node is a prompt with a set of responses (the key to the map is the id of Node - which you have to guarantee as being unique. Depending on which response matches, you can then then find the node in the map and hand control to that etc. Probably a little easier to deal with than a tree? Also give you the possibility of re-using states... NOTE: the XML above is really verbose, you can trim it down with attributes, my intention was to simply get the idea across...
It's an option to consider I guess...