What i want to do is similar in the following link but we want it using search:search:
Queries Constrained to Elements
Basically we have 2 xmls like the following:
XML-1
<rootElement>
<id>7635940284725382300</id>
<parentElement>
<childElement1>ce1-A</childElement1>
<childElement2>ce2-1</childElement2>
</parentElement>
<parentElement>
<childElement1>ce1-B</childElement1>
<childElement2>ce2-2</childElement2>
</parentElement>
<parentElement>
<childElement1>ce1-C</childElement1>
<childElement2>ce2-3</childElement2>
</parentElement>
</rootElement>
XML-2
<rootElement>
<id>7635940284725382398</id>
<parentElement>
<childElement1>ce1-A</childElement1>
<childElement2>ce2-2</childElement2>
</parentElement>
<parentElement>
<childElement1>ce1-B</childElement1>
<childElement2>ce2-3</childElement2>
</parentElement>
<parentElement>
<childElement1>ce1-C</childElement1>
<childElement2>ce2-4</childElement2>
</parentElement>
</rootElement>
So now what i want to do is to have a match for childElement1 and childElement2 within the same parentElement.
For example:
If i search with values childElement1 = ce1-B and childElement2 = ce2-3, it should only give me XML-2 and not return XML-1.
We have achieved this using the cts:search query as explained in the link:
cts:search (/,
cts:element-query (
xs:QName ('parentElement'),
cts:and-query ((
cts:element-value-query(xs:QName('childElement1'), 'ce1-B', 'exact'),
cts:element-value-query(xs:QName('childElement2'), 'ce2-3', 'exact')
))
)
)
Question:
We are using search:search with different search:constraints? I have read about using container for this but there are no good examples to show how it can be used.
Here is our sample search:search, so need to tweak this to have the same functionality as that shown by cts:search query shown above:
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
search:search("childElement1:ce1-B AND childElement2:ce2-3 sort:childElement2ASC"
, <options xmlns="http://marklogic.com/appservices/search">
<term>
<term-option xmlns="http://marklogic.com/appservices/search">unstemmed</term-option>
<empty apply="all-results" />
<term-option>case-insensitive</term-option>
<term-option>wildcarded</term-option>
</term>
<transform-results apply="transformed-result" ns="http://isearchgui/search" at="/customResultSet.xqy" />
<search:constraint name="childElement1">
<search:range type="xs:string" facet="false" collation="http://marklogic.com/collation/en">
<search:path-index ns="http://my.search.com/something">//childElement1</search:path-index>
</search:range>
</search:constraint>
<search:constraint name="childElement2">
<search:range type="xs:string" facet="false" collation="http://marklogic.com/collation/en">
<search:path-index ns="http://my.search.com/something">//childElement2</search:path-index>
</search:range>
</search:constraint>
<search:operator name="sort">
<search:state name="childElement1ASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://my.search.com/something">//childElement1</search:path-index>
</search:sort-order>
</search:state>
<search:state name="childElement1DES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://my.search.com/something">//childElement1</search:path-index>
</search:sort-order>
</search:state>
<search:state name="childElement2ASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://my.search.com/something">//childElement2</search:path-index>
</search:sort-order>
</search:state>
<search:state name="childElement2DES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://my.search.com/something">//childElement2</search:path-index>
</search:sort-order>
</search:state>
</search:operator>
</options>
, 0
, 15);
Hope this helps to answer.
You are on the right track. Use the container option, which works like any other constraint option, then wrap your nested query in parenthesis.
For example:
search:parse('contain:(test one two)',
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="contain">
<container>
<element ns="" name="parentElement"/>
</container>
</constraint>
</options>)
=>
<cts:element-query xmlns:cts="http://marklogic.com/cts">
<cts:element>parentElement</cts:element>
<cts:and-query>
<cts:word-query>
<cts:text xml:lang="en">test</cts:text>
</cts:word-query>
<cts:word-query>
<cts:text xml:lang="en">one</cts:text>
</cts:word-query>
<cts:word-query>
<cts:text xml:lang="en">two</cts:text>
</cts:word-query>
</cts:and-query>
</cts:element-query>
So in your case you would have the main-search string as :
search:search('contain:(childElement1:ce1-B AND childElement2:ce2-3) sort:childElement2ASC', <options ....)
Related
I want to convert the following schema from RNC/RNG to W3C XSD.
default namespace = ""
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
namespace rng = "http://relaxng.org/ns/structure/1.0"
start = starting_risk
starting_risk =
element risk {
element continents { Continents }?
}
Continents = element continent { Continent }+
Continent =
element country { Country }*,
element sea { Sea }*
Country = xsd:string { minLength = "1" maxLength = "100" }
Sea = xsd:string { minLength = "1" maxLength = "100" }
Using trang, I end up with
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="risk">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="continents"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="continents" type="Continents"/>
<xs:complexType name="Continents">
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="continent"/>
</xs:sequence>
</xs:complexType>
<xs:element name="continent" type="Continent"/>
<xs:complexType name="Continent">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="country"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="sea"/>
</xs:sequence>
</xs:complexType>
<xs:element name="country" type="Country"/>
<xs:element name="sea" type="Sea"/>
<xs:simpleType name="Country">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Sea">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
The problem is that the hierarchy is lost. The 'risk' element is the root of the schema and the only valid element at that level. In the RNC, the relationship between 'risk' and 'continent' elements is parent to child. But in the XSD, they are siblings. What am I doing wrong/ have I not understood?
You’re not doing anything wrong. I think unfortunately you just can’t use trang to generate an XSD from your RNC schema that preserves the restriction on what’s allowed as the root element.
You could instead manually create an XSD restricted to having risk be the only global element, with all the rest of the elements each being a local element. But (as far as I know) you can’t generate such an XSD using trang. The reason is that (again, as far as I know at least) trang basically always generates XSDs only with global elements.
You might think you could generate an XSD with local elements if you wrote your RNC like this:
start =
element risk {
element continents {
element continent {
element country { xsd:string { minLength = "1" maxLength = "100" } }*,
element sea { xsd:string { minLength = "1" maxLength = "100" } }*
}+
}?
}
That’s basically structured in the same way you’d want to structure your XSD if you did it manually.
But if you run that through trang to generate an XSD, you’ll find that every single element comes out as a global element in the resulting XSD. That’s just how trang always does it.
So unless there’s some magic way I’m unaware of to force trang to do otherwise, your only alternative if you want to restrict your XSD schema to only having risk allowed as the root element is, create the XSD manually.
I guess that could be seen as a design flaw in trang, but arguably the real problem is that XML Schema by design has nothing similar to RelaxNG’s start to explicitly specify a root element.
If XML Schema did have a similar simple way like RelaxNG’s start to specify what’s allowed as the root element, then trang could just output that in the XSD and you’d have what you want.
But because XSD has nothing like start, your only mechanism for restricting your schema to having only one particular root element is to completely (re)structure your XSD into the “local style”.
However, as mentioned earlier in this answer, you unfortunately can’t generate such a “local style” XSD from RelaxNG sources using trang. You instead must separately create the XSD manually.
It’s imaginable trang ideally could have been designed with some option to allow you to generate “local style” XSDs or maybe with some heuristics to somehow infer when that’s the output style it should use. But the reality is, that’s not the way trang actually works, and it’s not going to change.
So while I’m sure that isn’t the answer you were hoping to get, I hope it helps clarify things.
I'm migrating an app to the latest Debian and I get a strange server error when validating XML against a XSD
use strict;
use feature qw( :5.10.0 );
use XML::LibXML;
my $xsd = q{
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
};
my $soap=q{
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<shiporder
orderid="889923"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
<orderperson>John Smith</orderperson>
<shipto>
<name>Ola Nordmann</name>
</shipto>
</shiporder>
</soap:Body>
</soap:Envelope>
};
my $xmlparser = XML::LibXML->new();
my $doc = $xmlparser->parse_string($soap);
my $nodelist = $doc->getElementsByTagNameNS('http://schemas.xmlsoap.org/soap/envelope/', 'Body');
say $nodelist->[0]->toString();
XML::LibXML::Schema->new(string => $xsd)->validate($nodelist->[0]);
which causes
* glibc detected perl: free(): invalid pointer: 0x0000000001cca220 **
======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x76d76)[0x7fa0edd5fd76]
/usr/lib/perl5/auto/XML/LibXML/LibXML.so(PmmREFCNT_dec+0xa3)[0x7fa0ed27c543]
/usr/lib/perl5/auto/XML/LibXML/LibXML.so(XS_XML_LibXML_Node_DESTROY+0xeb)[0x7fa0ed260a4b]
/usr/lib/libperl.so.5.14(Perl_pp_entersub+0x58c)[0x7fa0ee7ce70c]
/usr/lib/libperl.so.5.14(Perl_runops_standard+0x16)[0x7fa0ee7c5ce6]
/usr/lib/libperl.so.5.14(Perl_call_sv+0x45b)[0x7fa0ee7619db]
/usr/lib/libperl.so.5.14(Perl_sv_clear+0x559)[0x7fa0ee7d4bd9]
/usr/lib/libperl.so.5.14(Perl_sv_free2+0x52)[0x7fa0ee7d5292]
/usr/lib/libperl.so.5.14(Perl_leave_scope+0x122f)[0x7fa0ee7fccef]
/usr/lib/libperl.so.5.14(Perl_pp_leave+0xf2)[0x7fa0ee7cb112]
/usr/lib/libperl.so.5.14(Perl_runops_standard+0x16)[0x7fa0ee7c5ce6]
/usr/lib/libperl.so.5.14(perl_run+0x3a5)[0x7fa0ee767815]
perl(main+0x149)[0x400f89]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7fa0edd07ead]
perl[0x400fc1]
======= Memory map: ======== 00400000-00402000 r-xp 00000000 08:01 137813 /usr/bin/perl
and so on
I think it is failing when trying to free the memory allocated. I've tried cloning the objects but nothing seems to stop it. This is failing on a clean install of wheezy and jessie
as #nwellnhof said in a separate answer, validate expects a document as a parameter, rather than a node
So I created a new document from the node and then it validates
my $xmlparser = XML::LibXML->new();
my $doc = $xmlparser->parse_string($soap);
my ($node) = $doc->findnodes('/soap:Envelope/soap:Body/*');
my $newDoc = XML::LibXML::Document->new("1.0");
$newDoc->setDocumentElement($node->cloneNode(1));
say $newDoc;
XML::LibXML::Schema->new(string => $xsd)->validate($newDoc);
The validate method in XML::LibXML::Schema only works with whole documents. libxml2 also provides xmlSchemaValidateOneElement but there are no bindings for this function in XML::LibXML.
EDIT: This was fixed in XML::LibXML 2.0112. Now you can pass nodes to validate.
I'm a newbie with XSD and pretty much at wits end.
What I need to do is somehow define a 'literal' element within an XSD file so that users can use it in an XML document.
For example:
In the XML document, I want to let a user be able to add an element like this:
<WordBoundary/>
but let the XSD file define not only the name 'WordBoundary' but also a list of Elements within which are of types defined elsewhere within the XSD.
Is this possible?
Updated to provide more information:
I am trying to write an XSD (or set of XSDs) which provide a library of pre-defined elements for an end-user to use.
The elements will ultimately be used to generate a Regular Expression but I want to hide the complexities of regular expressions from users as far as possible.
The XSD will use .NETs XSD.Exe to generate C# classes.
Currently I have defined elements like and and etc. which work fine but rely on their ultimate regex pattern being defined in code. Some of the elements have a Pattern attribute to allow fine tuning but this clutters up the XML document for users somewhat.
Examples of the built-up existing C# definitions:
const string BidMatch = #"(?<" + BidGroupName + ">" + DecimalNumberFragment + ")";
const string OfferMatch = #"(?<" + OfferGroupName + ">" + DecimalNumberFragment + ")";
const string BidOfferSpreadMatch = BidMatch + OptionalGap + RangeSeparatorFragment + OptionalGap + OfferMatch;
I therefore wanted to be able to refactor this so that all the regex patterns are moved from code into XSD definitions to form a library (or if it turns out not to be possible an XML file looked up by name) whereby there are primitives such as and and commonly-used but more complex structures such as etc.
So the use can use predefined elements like directly within their XML document but also be able to build up their own like this:
<Group captureName="MyCustomMatch">
<WordBoundary/>
<Digit/>
<Literal pattern="[xyz]" />
<AnyOf/>
<AnyOfChoice>
<DecimalNumber />
<Gap />
<DecimalNumber />
</AnyOfChoice>
<AnyOfChoice>
<LiteralText text="(" />
<DecimalNumber />
<LiteralText text=")" />
</AnyOfChoice>
<WordBoundary/>
</Group>
(In fact the prefined elements in the library would be build up the same way)
From the code point of view, I currently have AnyOf/Group etc. working by looking at the element type and calling a method to generate the pattern. For this to work, all these new Elements need to have a common ancestor, e.g. RegexLiteral, from which I can just read the Pattern attribute or whatever and add it into the full pattern.
I have tried extending a common type and trying to override its Pattern attribute to use a fixed attribute but XSD does not apparently allow this.
I am hoping this is just a limitation of my XSD knowledge rather than of XSD itself and hoping you clever guys know a way of achieving this.
Update2:
Thought I had it with this XSD fragment
<xs:complexType name="LiteralFragment" abstract="true">
<xs:attribute name="Pattern" type="xs:string" />
</xs:complexType>
<xs:complexType name="Fred">
<xs:complexContent >
<xs:extension base="LiteralFragment" >
<xs:attribute name="Pattern" type="xs:string" fixed="BBB" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
but XSD (and Xsd2Code for that matter) generate this rubbish code:
public partial class Fred : LiteralFragment
{
private string pattern1Field;
public Fred()
{
this.pattern1Field = "BBB";
}
[System.Xml.Serialization.XmlAttributeAttribute("Pattern")]
public string Pattern1
{
get { return this.pattern1Field; }
set { this.pattern1Field = value; }
}
}
which bombs because there are two XmlAttributeAttribute with "Pattern" being used.
What I need is an XSD generator that is intelligent enough to realise this and generate this code instead:
public partial class Fred : LiteralFragment
{
public Fred()
{
Pattern = "BBB";
}
}
Try this....
The XSD:
<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="root" type="TRoot"/>
<xsd:element name="WordBoundary">
<xsd:complexType/>
</xsd:element>
<xsd:element name="SomethingElse">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="TRoot">
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
And this XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SomethingElse>Text <WordBoundary/> another <WordBoundary/>...</SomethingElse>
</root>
Is this what you had in mind?
I have an xsd type which consists of some elements. One of the elements is defined like
<xs:element name="Parameters" type="ParametersType" /> where ParametersType is
<xs:complexType name="ParametersType">
<xs:sequence>
<xs:element name="Parameter"
type="ParameterType"
minOccurs="0"
maxOccurs="unbounded" />
<xs:element name="UserDefinedParameter"
type="xs:base64Binary"
minOccurs="0"
maxOccurs="1">
</xs:element>
</xs:sequence>
</xs:complexType>
That is, I have an array of Parameter type records. So I have 2 questions so far:
Ноw to initialize such array and how to work with it in Expression block;
How to tune mapping from incoming message of the same type to my message?
When we talk about arrays here we are really talking about nested, repeatable nodes within your message.
One solution is to decompose your array inside a loop in your orchestration.
This is not simple, but here is an example:
The code inside the various expression shapes:
Inside "Count array items"
intCountArrayItems = xpath(MyMessage, "count(XpathToParameterNodeInYourMessage)");
Inside "foreach array item"
intLoopIndex < intCountArrayItems
Inside "Use array item"
strXPathToArrayItem = System.String.Format("XpathToParameterNodeInYourMessage[{0}]", intLoopIndex + 1);
MyXmlDocument = xpath(MyMessage, strXPathToArrayItem);
// Now you can do what you want with the xml document.
Inside "Increment loop index"
intLoopIndex = intLoopIndex + 1;
The above gives you a way to decompose an array inside your orchestration and access each of your "Paramter" types as an xml document (which you can then do stuff with).
Hope this helps.
Basically if this was .NET, it would look like this:
ISomething
{
string A { get; }
int B { get; }
}
var somethings = new List<ISomething>();
something.Add(new SomethingSomething());
something.Add(new AnotherSomething());
something.Add(new AnythingSomething());
Basically I want the sequence of elements to be named anything they want to be, as long as their complex type is an extension of a complex type I define.
So it may look something like:
<somethings>
<something-something a="foo" b="0" />
<another-something a="bar" b="1" />
<example:anything-something a="baz" b="2" />
</somethings>
I'm sure this is possible, the alternative I guess is composition, where I have a standard element that can contain a single child that is at least a 'Something'..
Thanks in advance, xsd isn't my strong point.
Edit, ok the closest thing I've found so far is basically:
<somethings>
<something xsi:type="something-something" a="foo" b="0" />
<something xsi:type="another-something" a="bar" b="1" />
<something xsi:type="example:anything-something" a="baz" b="2" />
</somethings>
I guess this is the only way this is handled? if so this isn't so bad, and vs intellisense seems to understand this well enough.
Thanks.
This is a good question. You could do a sequence of "any", which would allow you have arbitrarily named elements inside - but that won't constrain them in any way. Alternately, the schema below constrains the name and the attributes, but nothing else (as in your second example)
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="somethingsType" >
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:attribute name="a" type="xs:string"/>
<xs:attribute name="b" type="xs:string"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="somethingsSeq" >
<xs:sequence>
<xs:element name="something" type="somethingsType"/>
</xs:sequence>
</xs:complexType>
<xs:element name="somethings" type="somethingsSeq"/>
</xs:schema>
I can't find a way to constrain the type but not the element name.