I have an xml like the following:
<table1>
<row>
<person>person1</person>
<value>10</value>
</row>
<row>
<person>person2</person>
<value>20</value>
</row>
<row>
<person>person1</person>
<value>5</value>
</row>
</table1>
<summaryTable>
<row>
<person>person1</person>
<value_total/>
</row>
<row>
<person>person2</person>
<value_total/>
</row>
</summaryTable>
With XForms 1 (there is no option to switch to XForms 2), using framework betterform, I want to calculate the values in the summary table, by doing the SUM of the rows in 'table1' that have the same person name. To do that I have the following binds:
<xf:bind id="bind_table1"
nodeset="table1" repeatableElement="row">
<xf:bind id="bind_head_table1" nodeset="head" />
<xf:bind id="bind_row_table1" nodeset="row">
<xf:bind id="bind_person" nodeset="person" type="xf:string" />
<xf:bind id="bind_value" nodeset="value" type="xf:integer" />
</xf:bind>
</xf:bind>
<xf:bind id="bind_summaryTable"
nodeset="summaryTable"
repeatableElement="row">
<xf:bind id="bind_head_summaryTable" nodeset="head" />
<xf:bind id="bind_row_summaryTable" nodeset="row">
<xf:bind id="bind_person_name" nodeset="person_name" type="xf:string" readonly="true"/>
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = ../person_name/text()]/value)"/>
</xf:bind>
</xf:bind>
What I want to have at the end is the value_total for person1 = 15 and value_total for person2 = 20, but using this 'calculate' expression I'm getting 'NaN'. If I replace the calculate expression to compare with a literal String like:
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = 'person1']/value)"/>
then I get as value_total 15 (the sum is correctly done). So it seems that the error is in the comparison expression person/text() = ../person_name/text() . Does someone have an idea about how should be the correct expression?
Thanks
Try the context() function in the calculate attribute to refer to the current node, like this:
<xf:bind nodeset="summaryTable/row/value_total" calculate="sum(//table1/row[person/text() = context()/../person/text()]/value)"/>
The context function gives you the current context node. If your bind references a nodeset with multiple nodes, it will be evaluated one time for every node, and that node is what context() returns.
It works for me with XSLTForms, maybe your version of betterForm supports it.
Related
Below is the XML
<on-error-continue type="APIKIT:BAD_REQUEST" enableNotifications="true" logException="true">
<set-variable value="200" doc:name="httpStatus" variableName="httpStatus" />
<set-variable value="Bad request" doc:name="logDescription" variableName="logDescription" />
<flow-ref doc:name="global-prepare-error-response-sub-flow" name="global-prepare-error-response-sub-flow"/>
</on-error-continue>
<on-error-continue type="APIKIT:TOO_MANY_REQUEST" enableNotifications="true" logException="true">
<set-variable value="200" doc:name="httpStatus" variableName="httpStatus" />
<set-variable value="Many request" doc:name="logDescription" variableName="logDescription" />
<flow-ref doc:name="global-prepare-error-response-sub-flow" name="global-prepare-error-response-sub-flow"/>
</on-error-continue>
Wanted to get the single record
"set-variable value="200" doc:name="httpStatus" variableName="httpStatus"
using xPath 1.0 expression: Parent is -->on-error-continue type="APIKIT:BAD_REQUEST" and child is -->set-variable value = "200".
Have tried below expression. It is working fine with Xpath2.0 but not working with 1.0
//*[local-name()='on-error-continue'][#*[local-name()='type' and .='APIKIT:BAD_REQUEST']]/set-variable[#value='200' and #variableName='httpStatus']
Using this handy website, I took the xml and put it in a root element, <root>YOUR XML</root>.
With this XPath:
//root/on-error-continue[#type='APIKIT:TOO_MANY_REQUEST']/set-variable[#value='200' and #variableName='httpStatus']
I was able to extract the matching record. Try it yourself and replace the root with * in the above XPath. You should see the records that you're seeking.
The wildcard operator can be used like any element in the path.
<foo>
<bar id="1" score="100" group="beginner" />
<bar id="2" score="200" group="beginner" />
<bar id="3" score="300" group="expert" />
...
</foo>
I try use like this, but something wrong (xpath 1.0)
foo/bar[#group='beginner' and not(#score<= preceding-sibling::bar/#score) and not(#score<=following-sibling::bar/#score)]
using xpath 1.0
/foo/bar[#group='beginner'][(not(preceding-sibling::bar[#group='beginner']/#score >= #score) and not(following-sibling::bar[#group='beginner']/#score > #score)) or (not(preceding-sibling::bar[#group='beginner']/#score <= #score) and not(following-sibling::bar[#group='beginner']/#score < #score))]/#score
I store a docx file in sql server database that contains negative number like -56653.
I installed Microsoft Filter Pack 2.0 and execute this code:
EXEC sp_fulltext_service 'update_languages';
EXEC sp_fulltext_service 'load_os_resources', 1;
EXEC sp_fulltext_service 'restart_all_fdhosts';
Then rebuild the Full Text Catalog multiple time, When search 56653, the query not found any things, but when search -56653 the query work fine.
SELECT *
FROM Files
WHERE
(CONTAINS([Files].[Content], '"56653"'))
Does somebody know what is the problem?
Finally I found the problem. Full text catalog not indexed content of table which inside a paragraph!
This mean the w:tbl tag move to outside of w:p tag.
<w:p w:rsidR="00E402AA" w:rsidP="00E402AA" w:rsidRDefault="00E402AA">
<w:pPr>
<w:bidi />
<w:spacing w:after="0" w:line="240" w:lineRule="auto" />
<w:jc w:val="both" />
<w:rPr>
<w:bCs />
<w:sz w:val="24" />
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:bCs />
<w:sz w:val="24" />
</w:rPr>
</w:r>
<!-- Start Table -->
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="TableGrid" />
<w:tblW w:w="5000" w:type="pct" />
</w:tblPr>
<w:tr>
<w:tc>
...
</w:tc>
</w:tr>
</w:tbl>
<!-- End Table -->
</w:p>
I'm currently working with VDA message types that have been convert to xml using a custom xml converter. However each header and line record in the source document is at the same level, as in the sample below:
<root>
<row>
<Record_type>512</Record_type>
<Customer_item_Number>A0528406</Customer_item_Number>
<Supplier_item_number>10962915</Supplier_item_number>
</row>
<row>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</row>
<row>
<Record_type>513</Record_type>
<Date>190306</Date>
<Quantity>97</Quantity>
</row>
<row>
<Record_type>512</Record_type>
<Customer_item_Number>A0528433</Customer_item_Number>
<Supplier_item_number>10962916</Supplier_item_number>
</row>
<row>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</row>
<row>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</row>
<row>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</row>
<row>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</row>
</root>
(512) record types are headers, the following (513) record types are lines for the preceding (512) record above it.
I am struggling to format this message, so that the lines (513) are indented underneath each header (512) record.
i.e. required output, something like this.
<root>
<Header>
<Record_type>512</Record_type>
<Customer_item_Number>A0528406</Customer_item_Number>
<Supplier_item_number>10962915</Supplier_item_number>
<Line>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</Line>
<Line>
<Record_type>513</Record_type>
<Date>190306</Date>
<Quantity>97</Quantity>
</Line>
</Header>
<Header>
<Record_type>512</Record_type>
<Customer_item_Number>A0528433</Customer_item_Number>
<Supplier_item_number>10962916</Supplier_item_number>
<Line>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</Line>
<Line>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</Line>
<Line>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</Line>
<Line>
<Record_type>513</Record_type>
<Date>170306</Date>
<Quantity>115</Quantity>
</Line>
</Header>
</root>
I have had some success using following sibling, but I'm unable to link this with preceding-sibling, to filter out only the required records before the next loop.
I am hoping someone will be able to assist. :)
In XQuery 3.1 you can use a tumbling window https://www.w3.org/TR/xquery-31/#id-tumbling-windows:
<root>
{
for tumbling window $record in root/row
start $s when $s/Record_type = 512
return
<Header>
{
head($record)/*,
tail($record) !
<Line>
{ * }
</Line>
}
</Header>
}
</root>
https://xqueryfiddle.liberty-development.net/gWcDMef
If your XQuery processor supports XQuery 3.0's window clauses, your query is (at least conceptually) very straight forward and efficient:
<root>{
for tumbling window $w in /root/row
start when true()
end next $n when $n/Record_type = '512'
return <Header>{
head($w)/*,
for $line in tail($w)
return <Line>{$line/*}</Line>
}</Header>
}</root>
Otherwise you have to use the preceding-sibling and following-sibling XPath axes as Mads Hansen also shows in his answer:
<root>{
for $header in /root/row[Record_type = '512']
return <Header>{
$header/*,
for $line in $header/following-sibling::row[Record_type = '513']
let $prev-headers := $line/preceding-sibling::row[Record_type = '512']
where $prev-headers[last()] is $header
return <Line>{$line/*}</Line>
}</Header>
}</root>
Here we get all lines after the current header first, and then check for each line if the last header before it is the current one. It is important here to use is instead of = or eq because the latter two work on atomic items only. This means that XML nodes are atomized (i.e., stripped down to just their concatenated text contents) before the comparison is performed. The is operator compares node identity instead.
For every row that has a Record_type of 512, create a Header element.
In order to find the row elements for the relevant group of Line elements, you want to select the row elements that are following-sibling from the 512 who's Record_type = 513 and who's first preceding-sibling is the current header.
for $header in $doc/root/row[Record_type = 512]
let $lines := $header/following-sibling::row[Record_type = 513]
[preceding-sibling::row[Record_type = 512][1] = $header]
return
<Header>{
$header/*,
for $line in $lines
return <Line>{ $line/* }</Line>
}</Header>
I have a XML column and i need help to write the query to display the nodes and their values.
below is the data from my xml column:
<item_content>
<stimulus_reference>
<table_wrapper>
<table frame="all" colsep="1" rowsep="1" pgwide="0">
<tgroup cols="3">
<thead>
<row>
<entry />
<entry align="center">Male</entry>
<entry align="center">Female</entry>
</row>
</thead>
<tbody>
<row>
<entry align="left">Juniors</entry>
<entry align="right">12</entry>
<entry align="right">3</entry>
</row>
<row>
<entry align="left">Seniors</entry>
<entry align="right">9</entry>
<entry align="right">21</entry>
</row>
</tbody>
</tgroup>
</table>
</table_wrapper>
<rationale>This is a rationale paragraph</rationale>
</stimulus_reference>
<task>
<item_stem>
<stem_paragraph>The table above shows the distribution of students that attended a concert, by class and gender.</stem_paragraph>
</item_stem>
<item_response>
<response_choices>
<columnar_choice_list>
<columns align="character" align_character="1">
<choice_row numeric_identifier="1">
CHROW1
<choice_cell>3</choice_cell>
</choice_row>
<choice_row numeric_identifier="2">
CHROW2
<choice_cell>15</choice_cell>
</choice_row>
<choice_row numeric_identifier="3">
CHROW3
<choice_cell>2102</choice_cell>
</choice_row>
<choice_row numeric_identifier="4">
CHROW4
<choice_cell>321</choice_cell>
</choice_row>
ColumnsData
</columns>
</columnar_choice_list>
</response_choices>
</item_response>
</task>
<math_expression>1+2=3</math_expression>
</item_content>
i want the output in the below format
Node_Name Node_val
stimulus_reference
table_wrapper
table
tgroup
thead
row
entry
entry Male
entry Female
tbody
row
entry Juniors
entry 12
entry 3
row
entry Seniors
entry 9
entry 21
task
item_stem
stem_paragraph The table above shows the distribution of students that attended a concert, by class and gender.
item_response
response_choices
columnar_choice_list
columns ColumnsData
choice_row CHROW1
choice_cell 3
choice_row CHROW2
choice_cell 15
choice_row CHROW3
choice_cell 2102
choice_row CHROW4
choice_cell 321
appreciate your help on this.
//* returns all nodes on all levels.
name() returns node name
text() returns node value
If you want only text nodes you have to replace //* with //*[text()]
select * from xmltable('//*' passing xmltype ('
<item_content>
<stimulus_reference>
<table_wrapper>
<table frame="all" colsep="1" rowsep="1" pgwide="0">
<tgroup cols="3">
<thead>
<row>
<entry />
<entry align="center">Male</entry>
<entry align="center">Female</entry>
</row>
</thead>
<tbody>
<row>
<entry align="left">Juniors</entry>
<entry align="right">12</entry>
<entry align="right">3</entry>
</row>
<row>
<entry align="left">Seniors</entry>
<entry align="right">9</entry>
<entry align="right">21</entry>
</row>
</tbody>
</tgroup>
</table>
</table_wrapper>
<rationale>This is a rationale paragraph</rationale>
</stimulus_reference>
<task>
<item_stem>
<stem_paragraph>The table above shows the distribution of students that attended a concert, by class and gender.</stem_paragraph>
</item_stem>
<item_response>
<response_choices>
<columnar_choice_list>
<columns align="character" align_character="1">
<choice_row numeric_identifier="1">
CHROW1
<choice_cell>3</choice_cell>
</choice_row>
<choice_row numeric_identifier="2">
CHROW2
<choice_cell>15</choice_cell>
</choice_row>
<choice_row numeric_identifier="3">
CHROW3
<choice_cell>2102</choice_cell>
</choice_row>
<choice_row numeric_identifier="4">
CHROW4
<choice_cell>321</choice_cell>
</choice_row>
ColumnsData
</columns>
</columnar_choice_list>
</response_choices>
</item_response>
</task>
<math_expression>1+2=3</math_expression>
</item_content>')
columns
node_name varchar2(100) path 'name()',
node_value varchar2(100) path 'text()'
)