Can someone tell me the exact difference between node() and element() types in XQuery? The documentation states that element() is an element node, while node() is any node, so if I understand it correctly element() is a subset of node().
The thing is I have an XQuery function like this:
declare function local:myFunction($arg1 as element()) as element() {
let $value := data($arg1/subelement)
etc...
};
Now I want to call the function with a parameter which is obtained by another function, say functionX (which I have no control over):
let $parameter := someNamespace:functionX()
return local:myFunction($parameter)
The problem is, functionX returns an node() so it will not let me pass the $parameter directly. I tried changing the type of my function to take a node() instead of an element(), but then I can’t seem to read any data from it. $value is just empty.
Is there some way of either converting the node to an element or should am I just missing something?
EDIT: As far as I can tell the problem is in the part where I try to get the subelement using $arg1/subelement. Apparently you can do this if $arg1 is an element() but not if it is a node().
UPDATE: I have tested the example provided by Dimitre below, and it indeed works fine, both with Saxon and with eXist DB (which is what I am using as the XQuery engine). The problem actually occurs with the request:get-data() function from eXist DB. This function gets data provided by the POST request when using eXist through REST, parses it as XML and returns it as a node(). But for some reason when I pass the data to another function XQuery doesn’t acknowledge it as being a valid element(), even though it is. If I extract it manually (i.e. copy the output and paste it to my source code), assign it to a variable and pass it to my function all goes well. But if I pass it directly it gives me a runtime error (and indeed fails the instance of test).
I need to be able to either make it ignore this type-check or “typecast” the data to an element().
data() returning empty for an element just because the argument type is node() sounds like a bug to me. What XQuery processor are you using?
It sounds like you need to placate static type checking, which you can do using a treat as expression. I don't believe a dynamic test using instance of will suffice.
Try this:
let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
Quoting from the 4th edition of Michael Kay's magnum opus, "The treat as operator is essentially telling the system that you know what the runtime type is going to be, and you want any checking to be deferred until runtime, because you're confident that your code is correct." (p. 679)
UPDATE: I think the above is actually wrong, since treat as is just an assertion. It doesn't change the type annotation node(), which means it's also a wrong assertion and doesn't help you. Hmmm... What I really want is cast as, but that only works for atomic types. I guess I'm stumped. Maybe you should change XQuery engines. :-) I'll report back if I think of something else. Also, I'm curious to find out if Dimitre's solution works for you.
UPDATE #2: I had backpedaled here earlier. Can I backpedal again? ;-) Now my theory is that treat as will work based on the fact that node() is interpreted as a union of the various specific node type annotations, and not as a run-time type annotation itself (see the "Note" in the "Item types" section of the XQuery formal semantics.) At run time, the type annotation will be element(). Use treat as to guarantee to the type checker that this will be true. Now I wait on bated breath: does it work for you?
EXPLANATORY ADDENDUM: Assuming this works, here's why. node() is a union type. Actual items at run time are never annotated with node(). "An item type is either an atomic type, an element type, an attribute type, a document node type, a text node type, a comment node type, or a processing instruction type."1 Notice that node() is not in that list. Thus, your XQuery engine isn't complaining that an item has type node(); rather it's complaining that it doesn't know what the type is going to be (node() means it could end up being attribute(), element(), text(), comment(), processing-instruction(), or document-node()). Why does it have to know? Because you're telling it elsewhere that it's an element (in your function's signature). It's not enough to narrow it down to one of the above six possibilities. Static type checking means that you have to guarantee—at compile time—that the types will match up (element with element, in this case). treat as is used to narrow down the static type from a general type (node()) to a more specific type (element()). It doesn't change the dynamic type. cast as, on the other hand, is used to convert an item from one type to another, changing both the static and dynamic types (e.g., xs:string to xs:boolean). It makes sense that cast as can only be used with atomic values (and not nodes), because what would it mean to convert an attribute to an element (etc.)? And there's no such thing as converting a node() item to an element() item, because there's no such thing as a node() item. node() only exists as a static union type. Moral of the story? Avoid XQuery processors that use static type checking. (Sorry for the snarky conclusion; I feel I've earned the right. :-) )
NEW ANSWER BASED ON UPDATED INFORMATION: It sounds like static type checking is a red herring (a big fat one). I believe you are in fact not dealing with an element but a document node, which is the invisible root node that contains the top-level element (document element) in the XPath data model representation of a well-formed XML document.
The tree is thus modeled like this:
[document-node]
|
<docElement>
|
<subelement>
and not like this:
<docElement>
|
<subelement>
I had assumed you were passing the <docElement> node. But if I'm right, you were actually passing the document node (its parent). Since the document node is invisible, its serialization (what you copied and pasted) is indistinguishable from an element node, and the distinction was lost when you pasted what is now interpreted as a bare element constructor in your XQuery. (To construct a document node in XQuery, you have to wrap the element constructor with document{ ... }.)
The instance of test fails because the node is not an element but a document-node. (It's not a node() per se, because there's no such thing; see explanation above.)
Also, this would explain why data() returns empty when you tried to get the <subelement> child of the document node (after relaxing the function argument type to node()). The first tree representation above shows that <subelement> is not a child of the document node; thus it returns the empty sequence.
Now for the solution. Before passing the (document node) parameter, get its element child (the document element), by appending /* (or /element() which is equivalent) like this:
let $parameter := someNamespace:functionX()/*
return local:myFunction($parameter)
Alternatively, let your function take a document node and update the argument you pass to data():
declare function local:myFunction($arg1 as document-node()) as element() {
let $value := data($arg1/*/subelement)
etc...
};
Finally, it looks like the description of eXist's request:get-data() function is perfectly consistent with this explanation. It says: "If its not a binary document, we attempt to parse it as XML and return a document-node()." (emphasis added)
Thanks for the adventure. This turned out to be a common XPath gotcha (awareness of document nodes), but I learned a few things from our detour into static type checking.
This works perfectly using Saxon 9.3:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
my:fun(their:fun2(/*) )
when the code above is applied on the following XML document:
<t>
<a/>
</t>
the correct result is produced with no error messages:
<a/>
Update:
The following should work even with the most punctuential static type-checking XQuery implementation:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
let $vRes := their:fun2(/*)
(: this prevents our code from runtime crash :)
return if($vRes instance of element())
then
(: and this assures the static type-checker
that the type is element() :)
my:fun(their:fun2(/*) treat as element())
else()
node() is an element, attribute, processing instruction, text node, etc.
But data() converts the result to a string, which isn't any of those; it's a primitive type.
You might want to try item(), which should match either.
See 2.5.4.2 Matching an ItemType and an Item in the W3C XQuery spec.
Although it's not shown in your example code, I assume you are actually returning a value (like the $value you are working with) from the local:myFunction.
Related
This is some simplified code I haven't tested as is (so it may contain errors) that demonstrates the problem I'm experiencing:
type Space is private;
--Depending on members of Space, determines whether Outer fully contains Inner
function Contains(Outer : Space; Inner : Space);
--Outer should fully contain Inner
type Nested_Space is
record
Inner : Space;
Outer : Space;
end record
with Dynamic_Predicate => Contains(Outer, Inner);
I haven't been able to find a convenient way to initialize a Nested_Space without failing the assert defined by the predicate. If I try to set the members of Inner first, the members of Outer are still wherever they defaulted. But if I try to set the members out Outer first, the members of Inner are still wherever they defaulted. Even if I tried forcing a default on either type, there's still no way to pick a default that will certainly be within the bounds of any arbitrary Nested_Space.
Even trying to initialize with something like
declare
My_Inner : Space := (...);
My_Outer : Space := (...);
My_NS : Nested_Space := (Inner => My_Inner, Outer => My_Outer);
begin
....
end;
I can't seem to keep it from failing the assert. I can come up with some pretty clunky ideas (such as adding an Initialized : Boolean to Nested_Space specifically to check in the predicate, or alternatively setting members of the two different Spaces) but I was hoping there might be a solution that doesn't affect the structure of the record for something not required for the use case.
GNAT solutions are welcome if there's no solution in the ARM.
Thanks in advance!
I haven't been able to find a convenient way to initialize a Nested_Space without failing the assert defined by the predicate. If I try to set the members of Inner first, the members of Outer are still wherever they defaulted. But if I try to set the members out Outer first, the members of Inner are still wherever they defaulted.
ARM 3.2.4 (35/3) says, "A Static_Predicate, like a constraint, always remains True for all objects of the subtype, except in the case of uninitialized variables and other invalid values. A Dynamic_Predicate, on the other hand, is checked as specified above, but can become False at other times. For example, the predicate of a record subtype is not checked when a subcomponent is modified." You seem to be saying that this is not followed, and the record predicate is checked when you assign to a record component. If so, then you have found a compiler error. That it fails for an aggregate seems to support this idea.
However, unless you post a compilable example that demonstrates your problem, we cannot be sure that this is a compiler error.
Assume having the following setup:
type My is new Integer;
type My_Acc is access My;
procedure Replace(Self : in out My_Acc; New_Int : Integer)
with Pre => New_Int /= Self.all, Post => Self'Old.all /= Self.all;
Note: Code above might not be fully valid, but I hope the concept is understandable.
Now what happens if Unchecked_Deallocation() is used on Self inside Replace
and a new Integer is allocated and set to Self (This should result in Self'Old pointing to a now invalid memory location)?
Does Ada keep kind of a snapshot where Self'Old points to the previous memory location, but before Unchecked_Deallocation() is executed?
If Self'Old would get invalid for use in the Post contract, how could you still access the previous value? Is it possible to create a manual snapshot in the Pre contract that can then be used in Post? Maybe it can be achieved using Ghost_Code?
I want to make everything in Spark, in case that changes something.
Edit: Fixed Self to in out as mentioned by Simon Wright.
Edit: Fixed type of Self to allow null
It may be that the latest versions of SPARK support access types; it used not to, at all.
First, your Not_Null_My_Acc needs to be a subtype of My_Acc, unless you meant it to be a type in its own right.
Second, you can’t deallocate Self inside Replace and allocate a new value; Self is in-mode, & hence not writable.
Third, you can’t apply ’Old to Self, because
warning: attribute "Old" applied to constant has no effect
What you can say is
Post => Self.all'Old /= Self.all;
In ARM 6.1.1(26ff) it says
Each X'Old in a postcondition expression that is enabled denotes a constant that is implicitly declared at the beginning of the subprogram body, entry body, or accept statement.
The implicitly declared entity denoted by each occurrence of X'Old is declared as follows:
...
X'Old : constant S := X;
... in other words, nothing fancy is expected, just a straight copy of (in this case) Self: not Self.all.
So, if your Replace deallocates Self, then Self’Old is a dangling reference, and erroneous.
I suggested previously that changing the postcondition to
Post => Self.all'Old /= Self.all;
would be safe; why wouldn’t that meet your requirements? is there something going on you haven’t told us about?
Note the subtle difference between Self’Old.all and Self.all’Old. The first one takes a copy of Self as it was before the call, which gets dereferenced after the call (by which time it’s pointing into hyperspace), while the second one dereferences the prior Self and copies the integer value it finds there; on return that’s still valid.
I'm an experienced programmer but have never before touched Go in my life.
I just started playing around with it and I found that fmt.Println() will actually print the values of pointers prefixed by &, which is neat.
However, it doesn't do this with all types. I'm pretty sure it is because the types it does not work with are primitives (or at least, Java would call them that, does Go?).
Does anyone know why this inconsistent behaviour exists in the Go fmt library? I can easily retrieve the value by using *p, but for some reason Println doesn't do this.
Example:
package main
import "fmt"
type X struct {
S string
}
func main() {
x := X{"Hello World"}
fmt.Println(&x) // &{Hello World} <-- displays the pointed-to value prefixed with &
fmt.Println(*(&x)) // {Hello World}
i := int(1)
fmt.Println(&i) // 0x10410028 <-- instead of &1 ?
fmt.Println(*(&i)) // 1
}
The "technical" answer to your question can be found here:
https://golang.org/src/fmt/print.go?#L839
As you can see, when printing pointers to Array, Slice, Struct or Map types, the special rule of printing "&" + value applies, but in all other cases the address is printed.
As for why they decided to only apply the rule for those, it seems the authors considered that for "compound" objects you'd be interested in always seeing the values (even when using a pointer), but for other simple values this was not the case.
You can see that reasoning here, where they added the rule for the Map type which was not there before:
https://github.com/golang/go/commit/a0c5adc35cbfe071786b6115d63abc7ad90578a9#diff-ebda2980233a5fb8194307ce437dd60a
I would guess this had to do with the fact that it is very common to use for example pointers to Struct to pass them around (so many times you'd just forget to de-reference the pointer when wanting to print the value), but no so common to use pointers to int or string to pass those around (so if you were printing the pointer you were probably interested in seeing the actual address).
I am writing code that needs to return a modified version of an XML node, without changing the original node in the parent document.
How can I copy/clone the node so that the original context will not be connected to/affected by it? I don't want changes made to this node to change the original node in the parent document, just to the copy that my function is returning.
What I'm looking for would be very similar to whatever cts:highlight is doing internally:
Returns a copy of the node, replacing any text matching the query
with the specified expression. You can use this function to easily
highlight any text found in a query. Unlike fn:replace and other
XQuery string functions that match literal text, cts:highlight matches
every term that matches the search, including stemmed matches or
matches with different capitalization. [marklogic docs > cts:highlight]
The easiest way to create a clone/copy of a node is to use the computed document node constructor:
document{ $doc }
If you are cloning a node that is not a document-node(), and don't want a document-node(), just a clone of the original node(), then you can XPath to select that cloned node from the new document-node():
document{ $foo }/node()
Just for completeness: in general, the standard XQuery Update Facility has copy-modify expressions that explicitly perform a copy. With no modifications, this is like explicit cloning.
copy $node := $foo
modify ()
return $node
I am not sure if MarkLogic supports this syntax or not though. As far as I know, it uses its own function library for updates.
In-memory XML nodes are not directly modifiable. Instead, you make your desired changes while constructing a new node. If you know XSLT, that can be a good way to do it. If not, you can use an XQuery technique called recursive descent.
I have a specification of a function that acts like a constructor. The specification of the function is
function Create_Controller return Type_Controller;
Also, in the specification file, I have the Type_Controller type, which is an access. I copy the relevant fragment:
type Type_Controller_Implementation;
type Type_Controller is access Type_Controller_Implementation;
So, this is what I've attempted:
function Create_Controller return Type_Controller
is
My_Controller : aliased Type_Controller_Implementation;
begin
return My_Controller'Access;
end Create_Controller;
I tried to compile the program without the aliased keyword, but then, the compiler says:
prefix of "Access" attribute must be aliased
So, I put the aliased keyword and the compiler now suggests that I should change the specification:
result must be general access type
add "all" to type "Controlador_De_Impresion" defined at controller.ads
The problem is that I'm not allowed to change the specification. I've read the chapter about access types in the Ada Programming Wikibook, but I still don't understand why my code doesn't work. What am I doing wrong?
The implementation of the Create_Controller function body is incorrect. Were it to work as coded, you'd be returning a pointer to a variable local to that function body's scope...which would be immediately lost upon returning from the function, leaving you with an invalid pointer.
No, an instance of the type needs to be allocated and returned. If there's no explicit initialization that needs to occur you can simply do:
return new Type_Controller_Implementation;
If there is some initialization/construction that has to occur, then:
function Create_Controller return Type_Controller
is
My_Controller : Type_Controller := new Type_Controller_Implementation;
begin
-- Set fields of My_Controller
...
return My_Controller;
end Create_Controller;
When you declare an access type as access T, you're saying that "this is a pointer to a T and it must point to objects of type T allocated from a pool". (That is, allocated with a new keyword.) When you declare an access type as access all T, you're saying that it can point either to a T allocated from a pool, or to an aliased variable of type T.
If the type is declared as access T and you can't change it, then all access values of the type have to point to something allocated with new. You can't make it point to a variable (even to a "global" variable that isn't located on the stack).
The reasons for this are historical, I think. The first version of Ada (Ada 83) only had "pool-specific types." You couldn't make an access value point to some other variable at all, without trickery. This meant that a compiler could implement access values as indexes into some storage block, or as some other value, instead of making them the actual address of an object. This could save space (an access value could be smaller than an address) or allow more flexibility in how pool memory was managed. Allowing access values to point directly to objects takes away some of that flexibility. I think that's why they decided to keep the old meaning, for backward compatibility, and require an all keyword to indicate the new kind of access.