Can we use user defined anchor for computed-bucket in range constraints? - anchor

I have some document content like this, and I have a range index on element "key".
<root>
<key>NAM</key>
<key>NA</key>
<key>North America</key>
</root>
When generating facets, I want to calculate the "NAM" and "NA" into one group instead each one of them.
So I tried to use the computed-bucket, more or less like this example:
<constraint name="date">
<range type="xs:dateTime" facet="true">
<element ns="http://example.com" name="entry"/>
<attribute ns="" name="date"/>
<computed-bucket lt="-P1Y" anchor="start-of-year" name="older">Older</computed-bucket>
<computed-bucket lt="P1Y" ge="P0Y" anchor="start-of-year" name="year">This Year</computed-bucket>
<computed-bucket lt="P1M" ge="P0M" anchor="start-of-month" name="month">This Month</computed-bucket>
<computed-bucket lt="P1D" ge="P0D" anchor="start-of-day" name="today">Today</computed-bucket>
<computed-bucket ge="P0D" anchor="now" name="future">Future</computed-bucket>
<facet-option>descending</facet-option>
</range>
</constraint>
But I noticed that the anchor is generally pre-defined by MarkLogic, so I am asking: can I use my own defined anchor, like a function below?
<computed-bucket ge="P0D" anchor="myAnchor.xqy" name="future">Future</computed-bucket>

You can use bucket instead of computed-bucket for a range that you define:
http://docs.marklogic.com/guide/search-dev/appendixa#id_80046
which would be something like:
<bucket name="N" lt="O" ge="N">Terms that start with N</bucket>
Hoping that helps,

Computed buckets are not an option for string values. And if buckets are too rigid, consider writing a custom facet. Here is an example of one that allows grouping value patterns:
https://github.com/grtjn/ml-constraints/blob/master/grouping-constraint.xqy
HTH!

Related

In custom Instrument, how can I include the duration in a value

I have a custom Instrument with a os-signpost-interval-schema that captures a "state" string. I would like the final plot value to be <state>: <duration>, but I don't know how to get the duration into the string.
My working schema is the following, which just stores the state itself in the column:
<os-signpost-interval-schema>
<id>state-interval</id>
<title>State Interval</title>
<subsystem>"..."</subsystem>
<category>"..."</category>
<name>"state"</name>
<start-pattern>
<message>?state</message>
</start-pattern>
<column>
<mnemonic>state</mnemonic>
<title>State</title>
<type>string</type>
<expression>?state</expression>
</column>
</os-signpost-interval-schema>
I would like to change the expression in the column to (str-cat ?state ": " ?duration), but that fails with:
Variable '?duration' must appear in a pattern element to be used in a later expression.
I don't see any way to compute this later in the graph, lane, or plot. I've also tried explicitly creating a <duration-column>, but that doesn't seem to change anything.
The rest of the pieces include the table:
<create-table>
<id>state-table</id>
<schema-ref>state-interval</schema-ref>
</create-table>
And the lane, which I would like to display as <state>: <duration> rather than just the duration:
<lane>
<title>State</title>
<table-ref>state-table</table-ref>
<plot>
<value-from>state</value-from>
</plot>
</lane>
This turns out to be impossible. Apple does not expose duration as a variable. It can be solved by writing a custom modeler, though this adds a lot of complexity.

Rails nokogiri parse XML file

I'm a little bit confused: could not find in web good examples of parsing xml with nokogiri...
example of my data:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<rows SessionGUID="6448680D1">
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote />
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>1</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-58</OfferName>
<PeriodMin>2</PeriodMin>
<PeriodMax>4</PeriodMax>
<PriceListDiscountCode>31087</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>41</Quantity>
<SupplierID>30</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>203.35</Price>
</row>
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote>[0451103079] Bosch,MTGC#0451103079</PriceListItemNote>
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>0</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-1303</OfferName>
<PeriodMin>3</PeriodMin>
<PeriodMax>5</PeriodMax>
<PriceListDiscountCode>102134</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>5</Quantity>
<SupplierID>666</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>172.99</Price>
</row>
</rows>
</root>
and ruby code:
...
xml_doc = Nokogiri::XML(response.body)
parts = xml_doc.xpath('/root/rows/row')
with the help of xpath i could do this? also how to get this parts object (row)?
You're on the right track. parts = xml_doc.xpath('/root/rows/row') gives you back a NodeSet i.e. a list of the <row> elements.
You can loop through these using each or use row indexes like parts[0], parts[1] to access specific rows. You can then get the values of child nodes using xpath on the individual rows.
e.g. you could build a list of the AnalogueCode for each part with:
codes = []
parts.each do |row|
codes << row.xpath('AnalogueCode').text
end
Looking at the full example of the XML you're processing there are 2 issues preventing your XPath from matching:
the <root> tag isn't actually the root element of the XML so /root/.. doesn't match
The XML is using namespaces so you need to include these in your XPaths
so there are a couple of possible solutions:
use CSS selectors rather than XPaths (i.e. use search) as suggested by the Tin Man
after xml_doc = Nokogiri::XML(response.body) do xml_doc.remove_namespaces! and then use parts = xml_doc.xpath('//root/rows/row') where the double slash is XPath syntax to locate the root node anywhere in the document
specify the namespaces:
e.g.
xml_doc = Nokogiri::XML(response.body)
ns = xml_doc.collect_namespaces
parts = xml_doc.xpath('//xmlns:rows/xmlns:row', ns)
codes = []
parts.each do |row|
codes << xpath('xmlns:AnalogueCode', ns).text
end
I would go with 1. or 2. :-)
First, Nokogiri supports XPath AND CSS. I recommend using CSS because it's more easily read:
doc.search('row')
will return a NodeSet of every <row> in the document.
The equivalent XPath is:
doc.search('//row')
...how to get this parts object (row)?
I'm not sure what that means, but if you want to access individual elements inside a <row>, it's easily done several ways.
If you only want one node inside each of the row nodes:
doc.search('row Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
doc.search('//row/Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
If you only want the first such occurrence, use at, which is the equivalent of search(...).first:
doc.at('row Price').to_xml
# => "<Price>203.35</Price>"
Typically we want to iterate over a number of blocks and return an array of hashes of the data found:
row_hash = doc.search('row').map{ |row|
{
AnalogueCode: row.at('AnalogueCode').text,
Price: row.at('Price').text,
}
}
row_hash
# => [{:AnalogueCode=>"0451103079", :Price=>"203.35"},
# {:AnalogueCode=>"0451103079", :Price=>"172.99"}]
These are ALL covered in Nokogiri's tutorials and are answered many times here on Stack Overflow, so take the time to read and search.

Adding numbers to variables in WebHarvest

I should start off by saying that I'm very new to javascript.
I need to feed a bunch of urls to webharvest based on a number. It's a long story why, but my url structure looks kind of like this:
http://www.example.com/foo/bar?page=0. ?page= increases by 25 each step. So the next page will be http://www.example.com/foo/bar?page=25 then http://www.example.com/foo/bar?page=50 and so forth. There's a maximum, which I can set by another variable, call it ${maxpages}.
So what I need to do is modify a variable to feed into the otherwise fully predictable url, so that the variable has 25 added to it each time. I'm thinking of doing a while loop, like this:
<var-def name="pageNo">0</var-def>
<while condition="${pageNo} < ${maxpages}">
<body>
<html-to-xml><http url="${url}?${pageNo}"/></html-to-xml>
<var-def name="pageNo">
<var name="pageNo">[this is where I want to add 25]</var>
</var-def>
</body>
</while>
So I'm really unsure of the syntax here.
My questions are:
How can I check that my variable pageNo is less than maxpages in the while condition?
Can you add integers to variables in webharvest? How?
I think I'm developing a habit of answering myself.
After an hour of trial and error, I have this:
<var-def name="commentCount">432</var-def>
<var-def name="pageNo">0</var-def>
<while condition="${pageNo.toInt() < commentCount.toInt()}">
<html-to-xml>
<http url="http://www.example.com/foo/bar?${pageNo}"/>
</html-to-xml>
<var-def name="pageNo"><template>${pageNo.toInt() + 25}</template></var-def>
</while>

Find child of child which attribute code is equal to the parameter passed on the url - XSL

On this dynamic website,
The url looks something like this : departments/CHEM.html
CHEM is a parameter.
<xsl:param name="dep" select="'CHEM'" />
a piece of the xml is below
<course acad_year="2012" cat_num="5085" offered="Y">
<term term_pattern_code="1" fall_term="Y" spring_term="N">fall term</term>
<department code="CHEM">
<dept_long_name>Department of Chemistry and Chemical Biology</dept_long_name>
<dept_short_name>Chemistry and Chemical Biology</dept_short_name>
</department>
</course> ....
I am trying to get the dept_short_name to use on my H1 tag, but I have not been successful.So far I tried
<h2><xsl:value-of select="course/department/[code={#$dep}]"/></h2>
Any suggestions??? Thanks!
Just use:
<xsl:value-of select="course/department[#code eq $dep]/dept_short_name"/>
Remember:
In XPath 2.0 (XSLT 2.0) use the eq operator for value comparissons -- it is more efficient than the general comparisson operator = which really, only, needs to be used when at least one of its operands is a sequence.
I would try this:
<xsl:value-of select="course/department[#code=$dep]/dept_short_name/text()"/>
That says: find the department element (inside a course element) whose code attribute is the value of parameter "dep", then find the dept_short_name child element, then get the text inside that element.
You have to use the # to say that "code" is an attribute, but "dep" should not have it. I think the {} notation is for use inside attributes of the non-XSLT elements of your stylesheet, so I wouldn't use it inside a value-of expression.

Problem with BizTalk multi-input map

I have a map that takes 2 input messages, like this:
<ns0:Root>
<InputMessagePart_0>
<root>
<Indicator>1</Indicator>
<NewValue>AAA</NewValue>
</root>
<InputMessagePart_0>
<InputMessagePart_1>
<root>
<Value>BBB</Value>
</root>
<InputMessagePart_1>
</ns0:Root>
(Lots of the nodes are not shown for clarity)
The ouput message looks like this:
<Root>
<Value>AAA</Value>
</Root>
(It's identical to InputMessagePart_1)
If the Indicator is 1, I want Value to be replaced with NewValue. If it's 0, I want Value to stay the same. I used a scripting functoid with code like this:
public string Get_Value(string indicator, string value, string newValue)
{
if(indicator == "1")
{
return newValue;
}
else
{
return value;
}
}
I'm running into problems due to the fact that Value might not actually occur in the original InputMessagePart_1 - if it doesn't, I want to create it. With the script above, even though Indicator is 1, I'm not getting a return string when Value doesn't exist.
Any suggestions?
Updated: I did some further testing by removing the if/then logic and just returned a hard-coded string from the functoid, and I get the same results... it seems that just having the empty input kills the entire functionality of the functoid...
You should want to use the Equal functoid and test whether the value is 1. You'll then feed the result to the input of two functoids:
First, to a Value Mapping functoid, which is connected to the <New Value> tag in the first part of the source schema.
Second, to a Logical Not functoid, which is then connected to another Value Mapping functoid connected to the <Value> tag in the second part of the source schema.
If the <Indicator>; tag does not contain the expected value 1 or is not present in the source message, the Logical Equal functoid will return False, and the second branch of the map will execute.
It doesn't matter whether the Value tag is present in the second part of the source schema. If it is not, either one of the Value Mapping functoids will create it in the destination.
If you definitely need to depend upon the <Indicator> tag, you might want to use the Logical Existence functoid, that returns whether any specified input node appears in the source message.
If all else fails using the mapper, you might try switching to XSLT - see here how to scrape the XSLT out of your existing BTM.
The map that you are after looks straightforward:
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > .. etc ... whatever you've scraped out
<xsl:output ...
<xsl:template match=...>
<ns1:Root>
<ns1:Value>
<xsl:choose>
<xsl:when test="/ns0:Root/ns0:InputMessagePart_0/ns0:root/ns0:Indicator/text()='1'">
<xsl:value-of select="/ns0:Root/ns0:InputMessagePart_0/ns0:root/ns0:NewValue/text()" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="/ns0:Root/ns0:InputMessagePart_1/ns0:root/ns0:Value/text()" />
</xsl:otherwise>
</xsl:choose>
<ns1:Value>
</ns1:Root>

Resources