Sublime text - snippet with capitalization of param first letter - sublimetext

I want to make snippet for Sublime Text 2 or 3 which will produce the following code:
initial - somename
with upper case - Somename
and somename is text which will be always different.
My draft for this:
<snippet>
<content><![CDATA[
initial - ${2:somename}
with upper case - ${2:somename}
]]></content>
</snippet>
But how can I uppercase only first letter in parameter?

Final variant:
<snippet>
<content><![CDATA[
initial - ${1:somename}
with upper case - ${1/(.+)/\u$1/g}
]]></content>
</snippet>

Related

Getting a node value depending on an another value at the same level

For each "item" node in the following XML structure, I want to select the corresponding "title" (the text nodes are located at the same level as the item nodes, I can't modify it).
The link between those two nodes will be the "ref" node which is a kind of primary key between the "item" and "title" trees.
Is it possible in XPath ?
I think it should be something like this: //root/item/../title[ref/text()=??????]/label
An example :
<root>
<item>
<ref>ITEM001</ref>
</item>
<item>
<ref>ITEM002</ref>
</item>
<item>
<ref>ITEM003</ref>
</item>
<item>
<ref>ITEM004</ref>
</item>
<title>
<ref>ITEM002</ref>
<label>Hello world!</label>
</title>
<title>
<ref>ITEM003</ref>
<label>Goodbye world!</label>
</title>
<title>
<ref>ITEM007</ref>
<label>This is a test!</label>
</title>
<title>
<ref>ITEM0010</ref>
<label>No this a question!</label>
</title>
</root>
The result would be:
ITEM001: empty
ITEM002: Hello world!
ITEM003: Goodbye world!
ITEM004: empty
Thanks in advance for your help.
I assume if you follow below steps you would get you desired output.
Step 1: Iterate through all the Items tag and capture all in an array.
Step 2: Using a loop on array use the below XPath to find the respective label value.
//title[contains(.,'')]/label.
Step 3: If you find an matching element then get the text of the label to display on console else display empty.

How does $TM_CURRENT_WORD operate in Sublime Text?

In the Sublime Text documents, I see the following definition for TM_CURRENT_WORD
$TM_CURRENT_WORD Current word under the cursor when the snippet was triggered.
I'm confused as to how I would use this in practice. Wouldn't the word under the cursor always be the one in the tabTrigger? I'm trying to use this argument to pass in an argument into the Sublime snippet but can't get it to run properly.
This snippet works fine for me:
<snippet>
<content><![CDATA[
Before you insert snippet cursor was in this "$TM_CURRENT_WORD" word.${0}
]]></content>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
<tabTrigger>word</tabTrigger>
<!-- Optional: Set a scope to limit where the snippet will trigger -->
<scope>text</scope>
</snippet>
there you can find very interesting example:
<snippet>
<content><![CDATA[ = $TM_CURRENT_WORD + 1]]></content>
<tabTrigger>++</tabTrigger>
<description>i = i + 1</description>
<scope>source.fortran</scope>
</snippet>

restrict xpath within nested element

I want to find all index terms by section, but sections are nested. Here is a simple example.
<chapter>
<section><title>First Top Section</title>
<indexterm text="dog"/>
<para>
<indexterm text="tree"/>
</para>
<section><title>SubSection</title>
<indexterm text="cat"/>
</section>
</section>
<section><title>Second Top Section</title>
<indexterm text="elephant" />
</section>
</chapter>
Is there any xpath expression to get a result like this:
First Top Section = ["dog", "tree"]
Subsection = ["cat"]
Second Top Section = ["elephant"]
Of course I get all the descendant indexterms under a section with an expression like this:
/chapter/section//indexterm
But indexterms can be inside other elements in a section--they're not necessarily children.
Is it possible to get indexterms specific to their parent section using xpath?
You can put a predicate at the section level:
/chapter/section[title = 'First Top Section']//indexterm
but this will include all indexterm elements under the given section, including those in subsections. To exclude them you could do something like
/chapter/section[title = 'First Top Section']//indexterm[count(ancestor::section) = 1]
to pick out those indexterm elements that have exactly one section ancestor (i.e. the "First Top Section" you started with).
More generally, if you have a reference to a specific section element then you can get all the indexterm elements inside it but not inside a subsection by first evaluating
count(ancestor-or-self::section)
as a number, and with the current section element as the context node, and then build up another expression
.//indexterm[count(ancestor::section) = thenumberyoujustcounted]
and evaluate that as a node set, again with the original section element as the context node.
If you can use XPath 2.0, you could do:
XML Input
<chapter>
<section><title>First Top Section</title>
<indexterm text="dog"/>
<para>
<indexterm text="tree"/>
</para>
<section><title>SubSection</title>
<indexterm text="cat"/>
</section>
</section>
<section><title>Second Top Section</title>
<indexterm text="elephant" />
</section>
</chapter>
XPath 2.0
for $section in //section
return concat($section/title,' - ["',
string-join($section//indexterm[ancestor::section[1] is $section]/#text,
'", "'),'"]
')
Output
First Top Section - ["dog", "tree"]
SubSection - ["cat"]
Second Top Section - ["elephant"]

XPath expression for selecting all text in a given node, and the text of its chldren

Basically I need to scrape some text that has nested tags.
Something like this:
<div id='theNode'>
This is an <span style="color:red">example</span> <b>bolded</b> text
</div>
And I want an expression that will produce this:
This is an example bolded text
I have been struggling with this for hour or more with no result.
Any help is appreciated
The string-value of an element node is the concatenation of the string-values of all text node descendants of the element node in document order.
You want to call the XPath string() function on the div element.
string(//div[#id='theNode'])
You can also use the normalize-space function to reduce unwanted whitespace that might appear due to newlines and indenting in the source document. This will remove leading and trailing whitespace and replace sequences of whitespace characters with a single space. When you pass a nodeset to normalize-space(), the nodeset will first be converted to it's string-value. If no arguments are passed to normalize-space it will use the context node.
normalize-space(//div[#id='theNode'])
// if theNode was the context node, you could use this instead
normalize-space()
You might want use a more efficient way of selecting the context node than the example XPath I have been using. eg, the following Javascript example can be run against this page in some browsers.
var el = document.getElementById('question');
var result = document.evaluate('normalize-space()', el, null ).stringValue;
The whitespace only text node between the span and b elements might be a problem.
Use:
string(//div[#id='theNode'])
When this expression is evaluated, the result is the string value of the first (and hopefully only) div element in the document.
As the string value of an element is defined in the XPath Specification as the concatenation in document order of all of its text-node descendants, this is exactly the wanted string.
Because this can include a number of all-white-space text nodes, you may want to eliminate contiguous leading and trailing white-space and replace any such intermediate white-space by a single space character:
Use:
normalize-space(string(//div[#id='theNode']))
XSLT - based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
"<xsl:copy-of select="string(//div[#id='theNode'])"/>"
===========
"<xsl:copy-of select="normalize-space(string(//div[#id='theNode']))"/>"
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<div id='theNode'> This is an
<span style="color:red">example</span>
<b>bolded</b> text
</div>
the two XPath expressions are evaluated and the results of these evaluations are copied to the output:
" This is an
example
bolded text
"
===========
"This is an example bolded text"
If you are using scrapy in python, you can use descendant-or-self::*/text(). Full example:
txt = """<div id='theNode'>
This is an <span style="color:red">example</span> <b>bolded</b> text
</div>"""
selector = scrapy.Selector(text=txt, type="html") # Create HTML doc from HTML text
all_txt = selector.xpath('//div/descendant-or-self::*/text()').getall()
final_txt = ''.join( _ for _ in all_txt).strip()
print(final_txt) # 'This is an example bolded text'
How about this :
/div/text()[1] | /div/span/text() | /div/b/text() | /div/text()[2]
Hmmss I am not sure about the last part though. You might have to play with that.
normal code
//div[#id='theNode']
to get all text but if they become split then
//div[#id='theNode']/text()
Not sure but if you provide me the link I will try

XPath / XQuery: find text in a node, but ignoring content of specific descendant elements

I am trying to find a way to search for a string within nodes, but excluding ythe content of some subelements of those nodes. Plain and simple, I want to search for a string in paragraphs of a text, excluding the footnotes which are children elements of the paragraphs.
For example,
My document being:
<document>
<p n="1">My text starts here/</p>
<p n="2">Then it goes on there<footnote>It's not a very long text!</footnote></p>
</document>
When I'm searching for "text", I would like the Xpath / XQuery to retrieve the first p element, but not the second one (where "text" is contained only in the footnote subelement).
I have tried the contains() function, but it retrieves both p elements.
Any help would be much appreciated :)
I want to search for a string in
paragraphs of a text, excluding the
footnotes which are children elements
of the paragraphs
An XPath 1.0 - only solution:
Use:
//p//text()[not(ancestor::footnote) and contains(.,'text')]
Against the following XML document (obtained from yours but added p s within a footnote to make this more interesting):
<document>
<p n="1">My text starts here/</p>
<p n="2">Then it goes on there
<footnote>It's not a very long text!
<p>text</p>
</footnote>
</p>
</document>
this XPath expression selects exactly the wanted text node:
My text starts here/
//p[(.//text() except .//footnote//text())[contains(., 'text')]]
/document/p[text()[contains(., 'text')]] should do.
For the record, as a complement to the other answers, I've found this workaround that also seems to do the job:
//p[contains(child::text()|not(descendant::footnote), "text")]

Resources