update xsl file with xmlstaret, grep or similar - xslt

I have a series of similar XSL files and to all of them, I have to add the same XSL element in a specific position.
Here you can find a portion of the XSL to be updated and the element to be inserted is
<xsl:call-template name="distributor.xsl"/>
and it has to be after the </mrd:distributionFormat> and before the <mrd:transferOptions> tags
Is there a way to automatize this update to all my XSL files using XmlStarlet grep or similar?
...
<mdb:distributionInfo>
<mrd:MD_Distribution>
<mrd:distributionFormat>
<mrd:MD_Format>
<mrd:formatSpecificationCitation>
<cit:CI_Citation>
<cit:title>
<gco:CharacterString>WCS</gco:CharacterString>
</cit:title>
<cit:date gco:nilReason="unknown"/>
<cit:edition>
<gco:CharacterString>2.0</gco:CharacterString>
</cit:edition>
</cit:CI_Citation>
</mrd:formatSpecificationCitation>
</mrd:MD_Format>
</mrd:distributionFormat>
<!-- call-template -->
<xsl:call-template name="distributor.xsl"/>
<!-- call-template -->
<mrd:transferOptions>
...
I tried with
xmlstarlet ed -P -S -L -s //mrd:MD_Distribution -t elem -i xsl:include -t attr -n "name" -v "distributor.xsl" main.xsl
where main.xsl is the file to be updated

After changed requirements
Following commmand inserts the desired xsl:call-template node where
you want (for details see my first posting),
xmlstarlet edit \
-i '//mrd:transferOptions[1]' \
-t elem -n 'xsl:call-template' -v '' \
-s '$prev' -t attr -n name -v 'distributor.xsl' \
main.xsl
when run on the following XML file (adjust namespaces as needed):
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cit="urn:so70244776_cit"
xmlns:gco="urn:so70244776_gco"
xmlns:mdb="urn:so70244776_mdb"
xmlns:mrd="urn:so70244776_mrd"
>
<xsl:template name="x">
<mdb:distributionInfo>
<mrd:MD_Distribution>
<mrd:distributionFormat>
<mrd:MD_Format>
<mrd:formatSpecificationCitation>
<cit:CI_Citation>
<cit:title>
<gco:CharacterString>WCS</gco:CharacterString>
</cit:title>
<cit:date gco:nilReason="unknown"/>
<cit:edition>
<gco:CharacterString>2.0</gco:CharacterString>
</cit:edition>
</cit:CI_Citation>
</mrd:formatSpecificationCitation>
</mrd:MD_Format>
</mrd:distributionFormat>
<mrd:transferOptions/>
</mrd:MD_Distribution>
</mdb:distributionInfo>
</xsl:template>
</xsl:transform>

In a POSIX shell the following xmlstarlet command:
xmlstarlet edit \
-N xsl="http://www.w3.org/1999/XSL/Transform" \
-N mdb="urn:so70244776_mdb" \
-N mrd="urn:so70244776_mrd" \
--var templatename "'distributor-N.xsl'" \
--var anchornode '//mrd:distributionFormat[1]' \
-d '$anchornode/following-sibling::xsl:call-template' \
-a '$anchornode' -t elem -n 'xsl:call-template' -v '' \
-a '$xstar:prev' -t attr -n name -v '' \
-u '$xstar:prev' -x '$templatename' \
main.xsl
declares a number of namespace bindings
selects //mrd:distributionFormat[1] as anchor node
deletes any existing xsl:call-template sibling nodes following the anchor
appends a new xsl:call-template element with a name attribute
xmlstarlet edit code can use the convenience $xstar:prev (aka
$prev) node to refer to the node created by the most recent
-i / --insert, -a / --append, or -s / --subnode option.
Examples of $xstar:prev are given in
doc/xmlstarlet.txt
and the source code's examples/ed-backref*.
In the command shown its first use refers to the xsl:call-template
element, the second to the name attribute.
EDIT: It turns out xmlstarlet edit isn't as picky as I thought
it was so an alternative, shorter command would be (attribute nodes
can be added with -s, -i, or -a):
xmlstarlet edit \
--var anchor '//mrd:distributionFormat[1]' \
-d '$anchor/following-sibling::xsl:call-template' \
-a '$anchor' -t elem -n 'xsl:call-template' -v '' \
-s '$prev' -t attr -n name -v 'distributor-N.xsl' \
main.xsl
Given the following (demo) input:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mdb="urn:so70244776_mdb"
xmlns:mrd="urn:so70244776_mrd"
>
<xsl:template name="q">
<mdb:distributionInfo>
<mrd:MD_Distribution>
<mrd:distributionFormat>
<mrd:MD_Format>
<mrd:formatSpecificationCitation/>
</mrd:MD_Format>
</mrd:distributionFormat>
<xsl:call-template name="distributor.xsl"/>
<!-- x -->
<xsl:call-template name="distributor-1.xsl"/>
<mrd:transferOptions/>
</mrd:MD_Distribution>
</mdb:distributionInfo>
</xsl:template>
</xsl:transform>
either command above produces the following output:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mdb="urn:so70244776_mdb" xmlns:mrd="urn:so70244776_mrd" version="1.0">
<xsl:template name="q">
<mdb:distributionInfo>
<mrd:MD_Distribution>
<mrd:distributionFormat>
<mrd:MD_Format>
<mrd:formatSpecificationCitation/>
</mrd:MD_Format>
</mrd:distributionFormat>
<xsl:call-template name="distributor-N.xsl"/>
<!-- x -->
<mrd:transferOptions/>
</mrd:MD_Distribution>
</mdb:distributionInfo>
</xsl:template>
</xsl:transform>

Related

BASH script to rename XML file to an attribute value

I have a lot of .xml files structured the same way:
<parent id="idvalue" attr1="val1" attr2="val2" ...>
<child attr3="val3" attr4="val4" ... />
<child attr3="val5" attr4="val6" ... />
...
</parent>
Each file has exactly one <parent> element with exactly one id attribute.
All of those files (almost 1,700,000 of them) are named as part.xxxxx where xxxxx is a random number.
I want to name each of those files as idvalue.xml, according to the sole id attribute from the file's content.
I believe doing it with a bash script would be the fastest and most automated way. But if there are other suggestions, I would love to hear them.
My main problem is that I am not able (don't know how) to get the idvalue in a specific file, so that I could use it with the mv file.xxxxx idvalue.xml command.
First I would iterate through the xml files using find:
find -maxdepth 1 -name 'part*.xml' -exec ./rename_xml.sh {} \;
The line above will execute rename_xml.sh for every xml file, passing the file name as command argument to the script.
rename_xml.sh should look like this:
#!/bin/bash
// Get the id using XPath. You might probably need
// to install xmllint for that if it is not already present.
// The xpath query will return a string like this (try it!):
//
// id="idvalue"
//
// We are using sed to extract the value from that
id=$(xmllint --xpath '//parent/#id' "$1" | sed -r 's/[^"]+"([^"]+).*/\1/')
mv -v "$1" "$id.xml"
Don't forget to
chmod +x rename_xml.sh
Use a proper XML handling tool to extract the id from the files. For example,
xsh:
for file in part.* ; do
mv "$file" $(xsh -aC 'open { shift }; echo /parent/#id' "$file").xml
done
Like I mentioned in my comment that I am not sure about the performance of XSLT in compared to bash scripts, but I created the XSLT for you to try out.
In the stylesheet below, Dire is the directory that contains the xml files.The select "tokenize(document-uri(.), '/')[last()]"
retrieves the filename and the second line concatenates the directory name with the filename to get the path of the file.The line with xsl:copy..is used to copy the entire xml.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxml="urn:schemas-microsoft-com:xslt" xmlns:random="http://www.microsoft.com/msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="collection('Dire/?select=*.xml')" >
<xsl:variable name="filename" select="tokenize(document-uri(.), '/')[last()]"/>
<xsl:variable name="filepath" select="concat('Dire/',$filename)"/>
<xsl:variable name="doc" select="document($filepath)"/>
<xsl:variable name="outname" select="$doc/parent/#id"/>
<xsl:result-document href="{$outname}.xml" method="xml">
<xsl:copy-of select="$doc/node()"/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I ran the xslt using saxon8. Unfortunately I could not find any way to rename the xml directly.But the above code should be worth a try.

DataPower file transfer returns base64

I am using below cURL command to get DataPower files from applaince to a remote Solaris server.
/usr/local/bin/curl -s --insecure --data-binary #getFile.xml -u username:password https://ip:port/service/mgmt/current
Content of getFile.xml is as below.
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<dp:request xmlns:dp="http://www.datapower.com/schemas/management">
<dp:get-file name="config:///unicenter.cfg"/>
</dp:request>
</env:Body>
</env:Envelope>
When I am running the cURL metioned above on Solaris, I am getting long base64 encoded string. But I wish to get the complete file copied to Solaris.
The long Base64-encoded string is your file. You need to do a little work to extract it.
This curl command is using the DataPower XML Management interface, and they call it that because all requests and responses are XML-formatted. You may not have seen it as the long string flew by, but it was wrapped in XML. Here's a sample response with a small payload:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<dp:response xmlns:dp="http://www.datapower.com/schemas/management">
<dp:timestamp>2014-10-23T17:12:39-04:00</dp:timestamp>
<dp:file name="local:///testfile.txt">VGhpcyBpcyBub3QgYW4gYWN0dWFsIGVtZXJnZW5jeS4K</dp:file>
</dp:response>
</env:Body>
</env:Envelope>
So, you have two jobs to do. First, get the Base64 string out of its XML wrapper, and second, decode it. There are a million ways to do this -- I'll give you one of them. Get a copy of XmlStarlet to do the extraction, and OpenSSL to do the Base64 decoding.
Then, pipe the curl output like so:
/usr/local/bin/curl -s --insecure --data-binary #getFile.xml -u username:password https://ip:port/service/mgmt/current \
| (xmlstarlet sel -T -t -v "//*[local-name()='file']" && echo) \
| fold -w 64 \
| openssl enc -d -base64 >this-is-the-real-file
Two quick notes -- the "&& echo" is to add a trailing newline, and the "fold" is to split the Base64 string into lines. A less finicky Base64 decoder wouldn't need these. I just picked "openssl" because most people already have it.

How to override template "folder_full_view_item.pt" only for a Custom Type?

This question has evolved in a confusing way. Some of its parts though, and specially some answers, might be useful for someone. Therefore I'll let this question unmodified and I'll try to reformulate the question here.
Overriding the template folder_full_view_item.pt with z3c.jbot will override the template for all Content Types.
How do I override it only for a single Content Type MyType in a Product with many types?
Having the following structure:
Folder (layout=folder_full_view)
Document (layout=document_view)
MyType (layout=mytype_view)
The default steps in Plone are:
The template folder_full_view.pt calls folder_full_view_item.pt via item.getObject().folder_full_view_item().
Products.CMFPlone's template folder_full_view_item.pt adds different ViewletManagers (abovecontenttitle etc.) and calls the item's layout via use-macro="item_macro".
The template of the item (document_view, mytype_view etc.) is included.
What I need is a way to override the template folder_full_view_item.pt. Calling in step #2 the overridden template folder_full_view_item.pt for MyType and Plone's folder_full_view_item.pt for all other Content Types.
UPDATE
It seems that the template folder_full_view_item.pt cannot be overriden (without using jbot). The call item.getObject().folder_full_view_item() in the template folder_full_view.pt doesn't seems to go through "queryMultiAdapter" neither.
I present here all the steps to reproduce it and confirm that folder_full_view_item is ignored:
Set the PLONE_HOME path and remove existing exaple.theme if necessary:
PLONE_HOME=/path/to/Plone-4.3.2
cd ${PLONE_HOME}/zeocluster/src
rm -rf ${PLONE_HOME}/zeocluster/src/example.theme
sed -i '/example\.theme/d' ${PLONE_HOME}/zeocluster/buildout.cfg
run buildout with develop.cfg:
sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/buildout -c ${PLONE_HOME}/zeocluster/develop.cfg
cd ${PLONE_HOME}/zeocluster/src
rm -rf /home/Plone-4.3.2/zeocluster/src/example.theme
sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/paster create \
--no-interactive \
--overwrite \
-o ${PLONE_HOME}/zeocluster/src \
-t plone3_theme example.theme \
expert_mode=all \
namespace_package=example \
package=theme \
skinname='ExampleTheme' \
skinbase='Sunburst Theme' \
empty_styles=False \
include_doc=True \
version=1.0 \
description='An installable theme for Plone 3' \
add_profile=True \
long_description= \
author= \
author_email= \
keywords='web zope plone theme' \
url='http://svn.plone.org/svn/collective/' \
license_name=GPL \
zip_safe=False \
zope2product=True
add example.theme to buildout:
sed -i '79i\ \ \ \ example.theme' ${PLONE_HOME}/zeocluster/buildout.cfg
sed -i '102i\ \ \ \ src/example.theme' ${PLONE_HOME}/zeocluster/buildout.cfg
register browser:pages
cat << EOF > ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/configure.zcml
<configure
xmlns:browser="http://namespaces.zope.org/browser"
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five"
xmlns:cmf="http://namespaces.zope.org/cmf"
xmlns:i18n="http://namespaces.zope.org/i18n"
i18n_domain="example.theme">
<five:registerPackage package="." initialize=".initialize" />
<include package=".browser" />
<include file="skins.zcml" />
<include file="profiles.zcml" />
<i18n:registerTranslations directory="locales" />
<browser:page
for="*"
name="folder_full_view_item"
template="folder_full_view_item.pt"
layer="example.theme.browser.interfaces.IThemeSpecific"
permission="zope2.View"
/>
<browser:page
for="Products.ATContentTypes.content.folder.ATFolder"
name="folder_full_view"
template="folder_full_view.pt"
layer="example.theme.browser.interfaces.IThemeSpecific"
permission="zope2.View"
/>
<browser:page
for="Products.ATContentTypes.content.document.ATDocument"
name="document_view"
template="document_view.pt"
layer="example.theme.browser.interfaces.IThemeSpecific"
permission="zope2.View"
/>
</configure>
EOF
copy original files (document_view.pt, folder_full_view.pt, and folder_full_view_item.pt) to theme:
cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/document_view.pt \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/document_view.pt
cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/folder_full_view_item.pt \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt
cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/folder_full_view.pt \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view.pt
slightly modify overriden templates to recognize them:
sed -i '/<metal:content-core define-macro="content-core">/a overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/document_view.pt' \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/document_view.pt
sed -i '/<metal:entries fill-slot="entries">/a overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/folder_full_view.pt' \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view.pt
sed -i '/<div tal:replace="structure provider:plone.abovecontenttitle" \/>/i overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt' \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt
chown -R plone_buildout example.theme
run buildout and start plone:
sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/buildout -c ${PLONE_HOME}/zeocluster/develop.cfg
${PLONE_HOME}/zeocluster/bin/zeoserver restart
${PLONE_HOME}/zeocluster/bin/client1 fg
If you want to programmatically create test data (e.g. from ipython) then you could do the following:
utils.sync()
plone_site_name = 'Plone'
# delete 'Plone' site if existing
if app.hasObject(plone_site_name): app.manage_delObjects(plone_site_name)
from Products.CMFPlone.factory import addPloneSite
# create 'Plone' site
plone_site = addPloneSite(
app,
plone_site_name,
profile_id=('Products.CMFPlone:plone',),
extension_ids=('plonetheme.classic:default',
'plonetheme.sunburst:default',),
setup_content=False,
)
plone_site = app[plone_site_name]
# install 'plone.app.theming' and 'example.theme'
plone_site.portal_quickinstaller.installProduct('plone.app.theming')
plone_site.portal_quickinstaller.installProduct('example.theme')
# create some content
plone_site.invokeFactory('Document', 'document')
folder_id = plone_site.invokeFactory('Folder', 'folder')
plone_site[folder_id].setLayout('folder_full_view')
plone_site[folder_id].invokeFactory('Document', 'document')
utils.commit()
UPDATE 2
Adding the following as suggested doesn't work either:
define a subclass from zope.interface.Interface:
cat << EOF >> ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/browser/interfaces.py
from zope.interface import Interface
class IMyLayer(Interface):
""" """
EOF
register it as a browser layer:
cat << EOF > ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/profiles/default/browserlayer.xml
<?xml version="1.0"?>
<layers>
<layer name="imylayer" interface="example.theme.browser.interfaces.IMyLayer" />
</layers>
EOF
register the browser:page for this layer:
sed -i 's/layer="example.theme.browser.interfaces.IThemeSpecific"/layer="example.theme.browser.interfaces.IMyLayer"/' \
${PLONE_HOME}/zeocluster/src/example.theme/example/theme/configure.zcml
UPDATE 3
The call item.getObject().folder_full_view_item() seems not to go through the "usual" layers!
I've tested the following with the example above:
in folder_full_view substitute the call item.getObject().folder_full_view_item() with item.getObject().document_view()
modify the original document_view.pt
echo "original document_view" > ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/document_view.pt
modify the document_view.pt in example.theme
echo "overriden document_view" > /home/Plone-4.3.2/zeocluster/src/example.theme/example/theme/document_view.pt
calling the document uses the overriden document_view.pt
curl -s 'http://localhost:8080/Plone/document' | grep "document_view"
overriden document_view
but calling the folder (with a document in it) uses the original document_view.pt
curl -s 'http://localhost:8080/Plone/folder' | grep "document_view"
original document_view
Thus the central questions seem to be:
goes the call item.getObject().template_name() in a template through the "usual" publishing/layers process?
If not, how to call a template like folder_full_view_item form folder_full_view and make it go trough the "usual" publishing/layers process?
Can someone give a hint for which part of zope/plone is responsible for this "publishing/layers process"?
Instead of overriding folder_full_view_item.pt you should rather create your own custom default template for your Content Type MyType.
Try using tal:condition="python:item_type=='MyType'" and item_type!='MyType' for different display needs. Hope this helpful.
To override this template you will need 2 things: a browser layer and the view that is going to be used in the context of your content type.
First, declare the browser layer:
from zope.interface import Interface
class IMyLayer(Interface):
"""A layer specific for this add-on product.
"""
This browser layer needs to be installed with your content type. Create a browserlayer.xml file with the following:
<?xml version="1.0"?>
<layers>
<layer name="my.type" interface="my.type.interfaces.IMyLayer" />
</layers>
Then, the view will be active when you are in the context of your content type and when your browser layer is active:
from five import grok
class FolderFullViewItem(grok.View):
"""Override folder_full_view_item for MyType.
"""
grok.context(IMyType)
grok.layer(IMyLayer)
grok.name('folder_full_view_item')
grok.template('folder_full_view_item')
grok.require('zope2.View')
On sc.blog we have a similar use case on which we override folder_summary_view and folder_full_view, take a look on it.
Also, don't forget to read the Layers chapter on the Plone Developers Documentation.
As the skins-tool seems to be deprecated and probably performance-losses would be involved, I'd rather go with a dedicated browser-view for your custom-contenttype, too, but to answer the question:
You can use collective.editskinswitcher (thanks to M. v. Rees!), without rewriting too much and even getting some nice and easy to configure dev-features along the way (visitors-view, while actually logged-in, via URL-distinction, e.g.).
In this case, we take advantage of the possibility to set the skin-property on a folderish contenttype-object and roughly, these steps should make the deal:
Place the customized folder_full_view_item.pt -template in any of your theme's skin-folders.
On creation of your contenttype, add an event-listener, which sets the freshly born object's skin_name to your theme's skin-name (have a look at c.editskinswitcher for methods and props, the referring HTTP-request is ##switchDefaultSkin?skin_name=YourTheme, btw).
Set another theme-skin as the global default for all other contextes in portal_skins-properties.

Removing specific tags in a KML file

I have a KML file which is a list of places around the world with coordinates and some other attributes. It looks like this for one place:
<Placemark>
<name>Albania - Durrës</name>
<open>0</open>
<visibility>1</visibility>
<description>(Spot ID: 275801) show <![CDATA[forecast]]></description>
<styleUrl>#wgStyle001</styleUrl><Point>
<coordinates>19.489747,41.277806,0</coordinates>
</Point>
<LookAt><range>200000</range><longitude>19.489747</longitude><latitude>41.277806</latitude></LookAt>
</Placemark>
I would like to remove everything except the name of the place. So in this case that would mean I would like to remove everything except
<name>Albania - Durrës</name>
The problem is, this KML file includes more than 1000 of these places. Doing this manually obviously isn't an option, so then how can I remove all tags except for the name tags for all of the items in the list? Can I use some kind of program for that?
Use a specialized command line tool that understands XML documents.
One such tool is xmlstarlet, which is available here for Linux, Windows and Solaris.
To address your particular problem, I used the xmlstarlet executable xml.exe like this (on Windows):
xml.exe sel -N ns=http://www.opengis.net/kml/2.2 -t -v /ns:kml/ns:Document/ns:Placemark/ns:name places.kml
This produces this output:
Albania - Durrës
Second Name
Third Name
...
Final Name
If you can guarantee that <name> occurs only as a child of <Placemark>, then this abbreviated version will produce the same result:
xml.exe sel -N ns=http://www.opengis.net/kml/2.2 -t -v //ns:name places.kml
(This is because this shorter version finds all <name> elements no matter where they occur in the document.)
If you really want an XML document, you'll need to do a little post-processing. Here's an example of a complete XML document:
<?xml version='1.0' encoding='utf-8'?>
<items>
<item>Albania - Durrës</item>
<item>Second Name</item>
<item>Third Name</item>
<!-- ... -->
<item>Final Name</item>
</items>
This first line is the XML declaration. It declares the Unicode encoding utf-8. You'll need to include this line so that XML processors recognize that your document includes Unicode characters. (As in Durrës.)
More: Here's an enhanced 'xmlstarlet' command that will produce the XML document above:
xml.exe sel -N ns=http://www.opengis.net/kml/2.2 -T -t -o "<?xml version='1.0' encoding='utf-8'?>" -n -t -v "'<items>'" -n -t -m //ns:Placemark -v "concat('<item>',ns:name,'</item>')" -n -t -o "</items>" -n places.kml
If you are on linux or similar:
grep "<name>" your_file.kml > file_with_only_name_tags
On windows, see What are good grep tools for Windows?

Access attributes from XML in shell

I'm trying to parse out values from a Widget config.xml using shell. I do want to use sed for this task. If there is something that sucks less than xsltproc, I'd love to know.
In this example I am after the id attribute value from the config.xml below:
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns="http://www.w3.org/ns/widgets" id="http://example.org/exampleWidget" version="2.0 Beta" height="200" width="200">
<name short="123">Foo Widget</name>
</widget>
I wish it was as simple as Jquery's attr: var id = $("widget").attr("id");
Currently this shell code utilising xsltproc fails:
snag () {
TMP=$(tempfile)
cat << EOF > $TMP
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="utf-8" indent="no"/>
<xsl:template>
<xsl:value-of select="$1"/>
</xsl:template>
</xsl:stylesheet>
EOF
echo $(xsltproc $TMP config.xml)
rm -f $TMP
}
ID=$(snag "widget/#id")
if test "$ID" = "http://example.org/exampleWidget"
then
echo Mission accomplished.
else
echo "<$ID> is wrong."
fi
XMLStarlet (http://xmlstar.sourceforge.net/) is a nice command line tools that supports such queries:
xmlstarlet sel -N w=namespace -T -t -m "/w:widget/#id" -v . -n config.xml
template match="widget"
select value-of="#id"
<xsl:template xmlns:wgt="http://www.w3.org/ns/widgets" match="/wgt:widget">
<xsl:select value-of="#id" />
</xsl:template>
You don't need XSLT if you're not doing a transform.
If you only need to grab a value use XPath.
There's an xpath program that comes with Perl's XML::XPath module.
From the shell:
ID=$(xpath config.xml 'string(/widget/#id)' )
( The string() function is to get only the value of the id.
/widget/#id by itself returns "id=value" )
If you only need to produce some other output depending on the value, you could
do it all in xslt. There are also other XPath implementations available from
other scripting languages: I've used Java's XPath from both rhino and Jython.
There's also XQuery from the command line with Saxon.