Loading xml in non-binary tree - c++

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...

Related

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.

XMLNS attribute removed by Slow Cheetah transformation

I'm trying to use Slow Cheetah to transform a Windows scheduled task config file. I'm simply trying to add "repetition" node information, like so:
ORIGINAL:
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2013-01-02T09:32:12.2196371</Date>
<Author>xxx</Author>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<StartBoundary>2013-01-10T01:00:00</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
.....
</Task>
REQUIRED, ADDITIONAL XML
<CalendarTrigger>
<Repetition>
<Interval>PT300S</Interval>
</Repetition>
</CalendarTrigger>
To do this, I have the following transformation file:
<?xml version="1.0" encoding="utf-16" ?>
<Task version="1.2">
<Triggers>
<CalendarTrigger xdt:Transform="Insert">
<Repetition>
<Interval>PT300S</Interval>
</Repetition>
</CalendarTrigger>
</Triggers>
</Task>
The problem I'm having is that all attributes outside of the CalendarTrigger node are removed (and therefore making the resultant transformation config an invalid scheduled task format).
I have tried adding
xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="SetAttributes" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"
to the Task node, but the attribute is then generated at CalendarTrigger level (and I cannot put this attribute on the original, because I then get "No element in the source document matches '/Task/Triggers' ").
Any pointers?
UPDATE:
The problem seems to be isolated to the xmlns attribute; if I try to include this in the 'Task' node of the original, I get "No element in the source document matches '/Task/Triggers'" - BUT changing this attribute to 'xmlns2' works fine and produces exactly what I need (albeit with an 'xmlns2' attribute!). Is this a known limitation of Slow Cheetah? Anyone know of a potential work-around?
That's because your xdt:Transform="Insert" is one level to high.
This should work:
<?xml version="1.0" encoding="utf-16" ?>
<Task xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Triggers>
<CalendarTrigger>
<Repetition xdt:Transform="Insert">
<Interval>PT300S</Interval>
</Repetition>
</CalendarTrigger>
</Triggers>
</Task>

how to add root node tag in a XML document with XSLT

Iam parsing the xml document in SSIS through the xmlsource. It does not have any root tag. So iam trying to add the root tag to my xml document through XSLT, but getting the error as
[XML Task] Error: An error occurred with the following error message: "There are multiple root elements. Line 11, position 2.".
what is the XSL to be used to add the root element.? Please help..this is very urgent..
Please find the xml source below
<organizational_unit>
<box_id>898</box_id>
<hierarchy_id>22</hierarchy_id>
<parent_box_id>0</parent_box_id>
<code>Team</code>
<description />
<name>CAPS Teams</name>
<manager_title />
<level>0</level>
</organizational_unit>
<organizational_unit>
<box_id>967</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>0</parent_box_id>
<code>main</code>
<description />
<name>Protegent</name>
<manager_title />
<level>0</level>
<organizational_unit>
<box_id>968</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>967</parent_box_id>
<code>19L</code>
<description>19L</description>
<name>19L</name>
<level>1</level>
<managers>
<manager>
<hierarchy_mgr_id>243</hierarchy_mgr_id>
<hierarchy_id>31</hierarchy_id>
<box_id>968</box_id>
<rep_id>19499</rep_id>
<unique_rep_id>100613948</unique_rep_id>
<first_name>Ed</first_name>
<last_name>Kill</last_name>
</manager>
</managers>
</organizational_unit>
<organizational_unit>
<box_id>1152</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>967</parent_box_id>
<code>UNKNOWN_m</code>
<description>Unknown Reps</description>
<name>Unknown Reps</name>
<level>1</level>
</organizational_unit>
</organizational_unit>
Well which XSLT processor do you use, how do you use it? I usually don't suggest to use string processing to construct XML but if you have a fragment without a root element then perhaps doing string concatenation "<root>" + fragment + "</root>" is the easiest way to get a well-formed document. XSLT can work with fragments but how you do that depends on the XSLT processor or XML parser you use, for instance .NET can use an XmlReader with XmlReaderSettings with ConformanceLevel set to fragment, which can then be loaded in an XPathDocument (for processing with XSLT 1.0 and XslCompiledTransform) and probably also with Saxon's XdmNode (although I am not sure I remember that correctly).
The stylesheet would then simply do
<xsl:template match="/">
<root>
<xsl:copy-of select="node()"/>
</root>
</xsl:template>
to wrap all top level nodes into a root element.

Translating itunes affiliate rss via xslt

I can't get this working for the life of me. Here is a snippet of the xml I get from an RSS feed from itunes affiliate. I want top print the values within tags but I cannot for some reason:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:im="http://itunes.apple.com/rss" xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<id>http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml</id><title>iTunes Store: Top Paid Applications</title><updated>2010-03-24T15:36:42-07:00</updated><link rel="alternate" type="text/html" href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewTop?id=25180&popId=30"/><link rel="self" href="http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml"/><icon>http://phobos.apple.com/favicon.ico</icon><author><name>iTunes Store</name><uri>http://www.apple.com/itunes/</uri></author><rights>Copyright 2008 Apple Inc.</rights>
<entry>
<updated>date</updated>
<id>someID</id>
<title>a</title>
<im:name>b</im:name>
</entry>
<entry>
<updated>date2/updated>
<id>someID2</id>
<title>a2</title>
<im:name>b2</im:name>
</entry>
</feed>
If I try <xsl:apply-templates match="entry"/> it spits out the entire contents of file. If I use <xsl:call-template name="entry"> it will show only one entry and I have to use <xsl:value-of select="//*[local-name(.)='name']"/> to get name but that's a hack. I've used xslt before for xml without namespaces and xml that has proper parent child relationships but not like this RSS feed. Notice entry is not wrapped in entries or anything.
Any help is appreciated. I want to use xslt because I want to alter the itunes link to go through my affiliate account - so something automated wouldn't work for me.
You are matching elements that are in no namespace, but the actual elements in the XML document do belong to a (deafult) namspace: xmlns="http://www.w3.org/2005/Atom".
Therefore, you need to declare the namespace in your stylesheet, let's say xmlns:atom="http://www.w3.org/2005/Atom". and then match not just on {elementName} but on {atom:elementName}, where {elementName} in your case is: "entry".

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.