XPath expression fails. (libxml2 in C) [closed] - c++

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm using libxml2 in a C program to do some stuff within XML documents.
Now... if I look to the following XPath I have an empty result.
/scheda_conservatore[1]/patrimonio_archivistico[1]/lower_list[#type='risorsa_informativa']/risorsa_informativa_nested[#id='037006-001-2012-ri002']
but... If I look for the following XPAth I have a non empty result containing elements that should have been matched even from the first one.
/scheda_conservatore[1]/patrimonio_archivistico[1]/lower_list/risorsa_informativa_nested[#id='037006-001-2012-ri002']
Now... if I check, step by step, my XPath I have...
/scheda_conservatore[1] -> Non empty node set
/scheda_conservatore[1]/patrimonio_archivistico[1] -> Non empty node set
/scheda_conservatore[1]/patrimonio_archivistico[1]/lower_list[#type='risorsa_informativa'] -> Empty Node set.
As I told before, the XML document DO contain a valid path but this is not matched by this request.
More: If I ask jEdit or other editors having XPath support to solve XPath expression for me, the result is a non empty node set.
I'm going mad. I watched the XPath expression thousands of times and there must be somethig very wrong at least as very hidden to my eyes even if it will surelly be brilliant to somebody else.
More...
The following, just asking for the 'type' attribute without looking at it's value, give a valid result. But the value is also correct.
/scheda_conservatore[1]/patrimonio_archivistico[1]/lower_list[#type]/risorsa_informativa_nested[#id='037006-001-2012-ri002']
Here's a "director's cut" of the larger XML document
<?xml version="1.0" encoding="iso-8859-1"?>
<scheda_conservatore anno_rilevazione="2012" stato="non-storicizzata">
<!-- scheda 2012 per Bologna -->
<patrimonio_archivistico>
<lower_list type="complesso_archivistico">
<complesso_archivistico_nested id="037006-001-2012-ca001" inventariazione="n">
<lower_list type="altro_luogo_collocazione">
<altro_luogo_collocazione_nested id="037006-001-2012-alc001">
<!-- altro luogo 1 per bologna 2012 -->
<upper_list type="complesso_archivistico">
<upper ref="ca002"/>
<upper ref="ca003"/>
</upper_list>
<ubicazione>sotterraneo da botola segreta</ubicazione>
<bridge_list type="sede">
<bridge ref="s001"/>
</bridge_list>
</altro_luogo_collocazione_nested>
</lower_list>
<!-- complesso 1 per bologna 2012 -->
<identificazione>
<denominazione>Archivi dei Comprensori della provincia di Bologna</denominazione>
<lista_altre_denominazioni>
<!-- Modificato -->
<altra_denominazione>Archivi dei Comprensori bolognesi</altra_denominazione>
<altra_denominazione>Archivi dei Comprensori felsinei</altra_denominazione>
</lista_altre_denominazioni>
<livello>Complesso di fondi, Superfondo</livello>
</identificazione>
<dati_giuridici>
<tipologia>Pubblico</tipologia>
<notificato_dichiarato presente="y">
<data>20100304T000000</data>
</notificato_dichiarato>
</dati_giuridici>
<lower_list type="titolare">
<titolare_nested id="037006-001-2012-t001">
<!-- titolare 1 per bologna 2012 -->
<upper_list type="complesso_archivistico">
<upper ref="ca001"/>
<upper ref="ca002"/>
</upper_list>
</titolare_nested>
</lower_list>
</complesso_archivistico_nested>
</lower_list>
<lower_list type="risorsa_informativa">
<risorsa_informativa_nested id="037006-001-2012-ri001">
<bridge_list type="complesso_archivistico">
<bridge ref="ca001"/>
<bridge ref="ca002"/>
</bridge_list>
<!-- risorsa 1 per bologna 2012 -->
<descrizione>
<autore>CSR - Centro studi e ricerche</autore>
<titolo>Atti degli uffici: inventario-mappa topografica del...</titolo>
<anno indicativo="y">1986</anno>
<qualifica>
<opz pubbl="y">Strumenti di ricerca archivistici</opz>
</qualifica>
<scelta_multipla nome="standard">
<opz valore="AACR2"/>
<opz valore="Altro">EAD</opz>
</scelta_multipla>
<descr_estrinseca>Dattiloscritto (relativo a: documentazione post 1945 conservata in Viale Martiri della Libert&#x2026;)</descr_estrinseca>
</descrizione>
<lista_pubblicazioni>
<pubblicazione>
<edita presente="y">stampa</edita>
<edita_stampa>
<curatore/>
<edito_in/>
<luogo/>
<data/>
<pagine/>
<sbn/>
<note/>
</edita_stampa>
<url/>
<ultima_consultazione>20120611T165400</ultima_consultazione>
<nota>Nessuna nota</nota>
</pubblicazione>
<pubblicazione>
<edita presente="y">web</edita>
<edita_stampa/>
<url>www.risorsainformativa.gov</url>
<ultima_consultazione/>
<nota>Nessuna nota web</nota>
</pubblicazione>
</lista_pubblicazioni>
<informatizzazione presente="y">
<scelta_multipla nome="applicativi_utilizzati">
<!-- MODIFICATO!! -->
<opz valore="Access (database)"/>
<opz valore="Altro">eXtraWay</opz>
</scelta_multipla>
<partecipazione_sistemi_informativi presente="y">
<descrizione>x.dams</descrizione>
</partecipazione_sistemi_informativi>
</informatizzazione>
</risorsa_informativa_nested>
</lower_list>
<lower_list type="intervento">
<intervento_nested autor_sovraintendenza="y" id="037006-001-2012-i001" in_corso="y">
<!-- intervento 1 per bologna 2012 -->
<descrizione>Restauro archivi dei comprensori della provincia di Bologna</descrizione>
<scelta_multipla nome="tipologia">
<opz valore="Riordino"/>
<opz valore="Altro">Pulizia</opz>
</scelta_multipla>
<avvio>20111101T000000</avvio>
<conclusione_prevista>20120701T000000</conclusione_prevista>
<conclusione_effettiva/>
<autore/>
<promotore/>
<scelta_multipla nome="standard_descrittivi">
<opz valore="ISAD"/>
<opz valore="Altro">Descrizione altro standard descrittivo</opz>
</scelta_multipla>
<informatizzazione presente="y">
<scelta_multipla nome="applicativo_utilizzato">
<opz valore="Access (database)"/>
<opz valore="Altro">eXtraWay</opz>
</scelta_multipla>
<partecipazione_sistemi_informativi presente="y">
<descrizione>x.dams</descrizione>
</partecipazione_sistemi_informativi>
</informatizzazione>
<bridge_list type="complesso_archivistico">
<bridge ref="ca001"/>
</bridge_list>
</intervento_nested>
</lower_list>
<note/>
</patrimonio_archivistico>
<note/>
<?xw-meta Dbms="ExtraWay" DbmsVer="24.3.1" OrgNam="3D Informatica" OrgVer="1.0" Classif="1.0" ManGest="3.1" ManTec="0.0.4" DocType="" InsUser="admin" InsTime="20120910175739" ModUser="rtirabassi" ModTime="20120925145347"?>
<?xw-crc key32=e324f581-406521b5?>
</scheda_conservatore>
Ok, now the problem is assuming another aspect. Probably I have to "close" this and pass to another quiestion.
XPath, on the originale (wider) XML document, is correct and now I see where the problem is but have no idea about how to solve it.
If I execute just once the XPath expression onto the XML document, I HAVE THE EXPECTED RESULT;
If I execute a pretty large sequence of XPath onto the same XML document, complex XPaths (containing condition concerning attribute values) fails (those ones and only those);
So I took a look on how we implemented the XPath evaluation and find that the XPathContext saw never freed. So I changed the code in order to free the context after each XPath evaluation and create a new one everytime but... nothing changes.
Any Idea?

XPath works correctly. You are looking for #id='037006-001-2012-ri002 and the attribute value is 037006-001-2012-ri001. After changing xml to ri002 it matches, libxml returns the correct nodesetval.
In case it does not really resolve the problem: maybe id attribute is treated in a special way? Try changing it to idx. See Java XML DOM: how are id Attributes special?

Ok, find the question.
Sorry for this false alarm. libxml2 works properly but there were changes into the XML document, during a cycle of XPath evaluations, that changed the scenario causing me to believe the XPath processor was failing.
The deep debugging session showed us that something else was wrong and only he XPath expression having a condition on an attribute (but not the last condition) failed. This drove us to the solution.
My fault. Sorry.

Related

Applying Conditional Logic using XSL

I have an XML document where I get several addresses for a member as address type PRIMARY, MAILING etc. however I only want to read the address as PRIMARY, MAILING when memberId is '0'. Please see the sample xml below.
<core>
<address>
<postalZipCode>90017</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>LOS ANGELES</city>
<stateProvince>CA</stateProvince>
<type>MAILING</type>
<line1>818 WEST SEVENTH STREET</line1>
</address>
<address>
<postalZipCode>95014</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>CUPERTINO</city>
<stateProvince>CA</stateProvince>
<type>PRIMARY</type>
<line1>1234 XYZ STREET</line1>
</address>
<memberId>0</memberId>
</core>
The XSL condition I am trying to evaluate in my XSLT file is as below -
<xsl:template match="core">
<xsl:when test="memberId[.='0'] and address/type[.='PRIMARY']">
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="data">
<fo:block>Line 1</fo:block>
</fo:table-cell>
</fo:table-row>
But this condition check is not working and address is not rendered in the generated document .
Could the experts here please suggest how do I go about such conditional check ?
First, you can't have <xsl:when> as a child of anything other than <xsl:choose>. I suspect in this case you probably meant to use <xsl:if>.
Secondly, your template matches core, not the primary address element- Not sure if this is intentional or not though.
Thirdly, your template doesn't actually output anything from the source document anyway, unless there's some missing from what you've included here.
As a rule it's generally advisable to write templates with predicates that fit your conditions, rather than explicit conditional logic within a template. I think what you probably want to do is:
<xsl:template match="core[memberId='0']/address[type='PRIMARY']">
<fo:etc..
</xsl:template>

pre-processing script to switch product codes

I have a snippet of code I've inherited and I'm trying to get it to work on multiples of the match pattern and set a tag from looking up a value from a table using another tag. What happens is that, for every item, the same lookup is performed and not the relative one for the node. I can't work out the syntax to work thru all entries and substitute the correct one. It's got to be simple it's just that I am simpler :)
My source xml contains this (within an outer /oomsdoc document node not shown):
<item>
<lineqty> 1</lineqty>
<linesku>BNLP5008 </linesku>
<linecustprod>xxxxxxxxxxxxxxx</linecustprod>
<linedesc>London Pride (Bot500mlx8) </linedesc>
</item>
<item>
<lineqty> 1</lineqty>
<linesku>BNBL5008 </linesku>
<linecustprod>xxxxxxxxxxxxxxx</linecustprod>
<linedesc>Bengal Lancer (Bot500mlx8) </linedesc>
</item>
I want to substitute the xxxxxxxxxxxxxxx in each linecustprod tag with the material from the lookup table using the value of the linesku tag.
This is my lookup table:
<Materials>
<product sku='BNLP5008 ' material='LONDON PRIDE'/>
<product sku='BNBL5008 ' material='BENGAL LANCER'/>
</Materials>
and this is my xslt code.
<xsl:variable name="SkuList" select="document('d:\test\transforms\catalogue.xml')/Materials"/>
<xsl:template match="/oomsdoc/item/linecustprod">
<xsl:variable name="MySku" select="/oomsdoc/item/linesku"/>
<linecustprod>
<xsl:value-of select="$SkuList/product[#sku=$MySku]/#material"/>
</linecustprod>
</xsl:template>
I'm guessing some kind of xsl foreach would work but just can't find a usable example to crib :)
Your guidance again would be appreciated at this point in my frustration :)
Thanks,
Brian.
Changing the variable definition to
<xsl:variable name="MySku" select="../linesku"/>
should be sufficient, this will pull out the linesku that is a sibling to the linecustprod you're currently looking at. As currently defined the variable will contain a node set of all the linesku elements in the document, so the value-of will give you the first entry from $SkuList that matches any entry in the main input file.
In addition to Ian Roberts' answer, please change
<xsl:variable name="SkuList" select="document('d:\test\transforms\catalogue.xml')/Materials"/>
to
<xsl:variable name="SkuList" select="document('/d:\test\transforms\catalogue.xml')/Materials"/>
for some reason, the first throws an error (malformed URL).

Unexpected behaviour of the XPath-axis preceding

I tried to make a list of all different values of the attribute year from the following XML
<Parts>
<Part Name="S1">
<Year year="2018" i="1"/>
<Year year="2017" i="2"/>
<Year year="2018" i="3"/>
<Year year="2017" i="4"/>
</Part>
</Parts>
with XSLT (with ant 1.8.2), using the axis preceding
<xsl:template match="/">
<xsl:for-each select="//Year [not( #year = preceding::Year/#year)]">
<xsl:sort select="#year" order="ascending" />
year: <xsl:value-of select="#year"/> -- <xsl:value-of select="./#i"/>
<br/><hr/>
</xsl:for-each>
</xsl:template>
getting the result
year: 2017 -- 2
year: 2018 -- 1
year: 2018 -- 3
I don't know, why I've got two times the "2018" (it is always the first of the selected elements giving the double).
With the axis preceding-sibling I get the expected result, a list with every value once:
year: 2017 -- 2
year: 2018 -- 1
Has anybody an explanation for this behaviour? I supposed preceding and preceding-sibling giving the same result in this example.
MK
Edit: Thanks for the comments.
I use the Java SE JDK 1.7.0
In the next time I will try to replace the processor by another implementation.
Last I knew, the version of Xalan packaged with the Sun JDKs was ancient and buggy. As Michael suggests, I would STRONGLY recommend obtaining the Apache versions until and unless Sun/Oracle fixes that.
(The XSLT processor packaged with IBM's JDKs is much less buggy -- it was being maintained in parallel with the Apache code until relatively recently, when that was replaced by a new processor written inside IBM. Alas, the IBM JDKs are not available separately; they ship only bundled with an IBM product that uses them.)

Refer to specific cell in xslt import/export filter for Calc

I am using xslt filter for importing/exporting data from Calc worksheet. Is it possible to refer to a specific cell address ? For example, if we want to export data from cell B2, how do we refer to this cell address in export xslt ?
Without knowing much about Openoffice or their xslt filter function, I can tell you that you're probably going to need a fairly simple XPath to reference a specific Cell's data - I doubt it would be as simple as calling getCell('B2') unless they have provided you with some custom xslt functions (I'm assuming they've put you in a raw XSLT environment).
Anyway, I think this question may be more about XSLT and xpath, than it is about openoffice. With that in mind, I'm going to fashion my own sample xml and examples and hopefully that will be enough to get you started.
For an input xml that looks something like this:
<ooo_calc_export>
<ooo_sheet num="1" name="sheet1">
<ooo_row num="2">
<fisrtCell>Oh</firstCell>
<secondCell>Hai</secondCell>
<thirdCell>There</thirdCell>
</ooo_row>
<ooo_row num="3">
<fisrtCell>Oh</firstCell>
<secondCell>Hello</secondCell>
<thirdCell>Back!</thirdCell>
</ooo_row>
</ooo_sheet>
</ooo_calc_export>
An absolute XPath to access cell B2's data would look like this ooo_calc_export/ooo_sheet/ooo_row[#num='2']/secondCell/text()
But the above is an absolute path and in XSLT, we would often author relative xpaths as we are in the midst of processing a document. Imagine you're in a template which matches on the ooo_calc_export node and you wanted to store Cell B2's data in a variable for later use. Consider this example:
<xsl:template match="/ooo_calc_export">
<!-- a relative xpath does not being with a forward slash -->
<xsl:variable name="B2" select="ooo_sheet/ooo_row[#num='2']/secondCell/text()" />
</xsl:template>
Now lets imagine you wanted a template to match on the cell B2 node itself:
<xsl:template match="ooo_row[#num='2']/secondCell">
<!-- a relative xpath does not being with a forward slash -->
<xsl:variable name="B2_text" select="text()" />
</xsl:template>
This is a good tutorial on XSLT to get you started. Also, the W3 Schools references on XPath and XSLT aren't the worst.

libxml2 XPATH - Selecting subset of data from XML

I am fairly new to XML dev.. I had a few questions regarding XML parsing with XPATH and libxml.
I have an XML structured as :
<resultset>
<result count=1>
<row>
<name> He-Man! </name>
<home> Greyskull </home>
<row>
</result>
<result count=2>
<row>
<name> Spider-Man</name>
<home> Some downtown apartment </home>
<row>
<row>
<name> Disco-Man!</name>
<home> The 70's dance floor </home>
<row>
</result>
<resultset>
I need to pick out the names from this XML , but where the count is 2 , i need it only from the first record. I ran through a few tutorials, but i am unable to come up with an XPATH query which would serve this purpose.
/name will select all name elements.
/result[#count > 1 ]/row[1]/name | /result[#count =1 ]/row/name
Is this possible to be done with XPATH ? Is this better to be done via XPATH or by walking the XML tree?
Can some one point me to some complex searches through out XML's ?
Edit : The actual scenario requires select a subset of the XML row , which are nested at 2 levels at times. This sounds like i need to OR '|' many paths to select the nodes i require... I am not sure if that would be efficient as opposed to walking a tree... The above is typed to replicate the problem :)
Thanks!
Try this XPath -
/resultset/result[#count=2]/row/name
This will give a list of all nodes falling under this XPath. From this just take the first element (as you needed only the first record).
I'd probably keep my xpath simpler and just extract both cases, then loop over both node sets.
If you do need to go down the single xpath route, you should try out your xpath expressions in something that lets you enter them live, rather than having to recompile C/C++ code. You should be able to do that by loading your XML into firefox and using firebug - for example typing $x('//name') in the firebug console gives three nodes.
NOTE however that your XML is invalid... You have a bunch of "<row>"s that should be "</row>" and the same for "<resultset>" and your counts need to be
<result count="1">
i.e. with quote marks around the value.