Mam następujący xml do parsowania i rozpakowywaniawartość tagu na podstawie wartości tagu. Wyodrębnij tylko wtedy, gdy typ == "hostowany". Chciałbym wyodrębnić za pomocą narzędzi bash, takich jak grep, sed i awk. Wyodrębnianie wartości pojedynczego tagu bez warunku jest czymś, co zrobiłem wcześniej, a nie warunkami. Mogę łatwo zrobić to za pomocą pythona lub dowolnego innego języka programowania, jaki znam. Ale byłoby to idealne, gdyby zostało zrobione w skrypcie powłoki.
...
<repositories-item>
<name>hosted-npm</name>
<type>hosted</type>
</repositories-item>
<repositories-item>
<name>proxied-npm</name>
<type>proxied</type>
</repositories-item>
...
Odpowiedzi:
3 dla odpowiedzi № 1xmlstarlet jest zestawem narzędzi XML do wiersza poleceń, który może wyrażać złożone szablony XSLT jako krótką sekwencję przełączników linii poleceń.
Załóżmy, że mamy do dyspozycji dobrze sformułowany dokument XML repos.xml
<repositories>
<repositories-item>
<name>hosted-npm</name>
<type>hosted</type>
</repositories-item>
<repositories-item>
<name>proxied-npm</name>
<type>proxied</type>
</repositories-item>
</repositories>
Jeśli uruchomisz go za pomocą filtra XMLStarlet z następującymi przełącznikami
$ cat repos.xml | xmlstarlet sel -t -m "//repositories-item"
-i "type="hosted"" -v "name" -n
Otrzymasz jedną linię danych wyjściowych
hosted-npm
Spójrzmy na wiersz poleceń XMLStarlet.
- Uruchomimy polecenie w trybie Select określonym za pomocą
sel
przełącznik - Określamy szablon wyboru z
-t
przełącznik - Ograniczamy parser do
<repositories-item>
elementy z//repositories-item
szablon określony za pomocą-m
swicth - Wybieramy tylko te elementy, które "hostowane" jako wartość
type
element określony za pomocą-i
przełącznik - Drukujemy wartość
name
element, określony przez-v
przełącznik. - Po każdym wierszu wyjścia drukujemy znak nowej linii określony przez
-n
przełącznik.
Oto odpowiednik XSLT generowanego przez XMLStarlet
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//repositories-item">
<xsl:choose>
<xsl:when test="type="hosted"">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name"/>
</xsl:call-template>
<xsl:value-of select="" ""/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="" ""/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Zgodnie z sugestią Charlesa Duffy'ego warto zauważyć, że ta specyfikacja XSLT może zostać wygenerowana za pomocą XMLStarlet przy użyciu -C
opcja:
xmlstarlet sel -C -t -m "//repositories-item"
-i "type="hosted"" -v "name" -n > hosted-repos.xslt
Ta wygenerowana specyfikacja XSLT może być bezpośrednio używana z xsltproc
tak jak
cat repos.xml | xsltproc hosted-repos.xslt -
0 dla odpowiedzi nr 2
brakuje narzędzi specyficznych dla xml
awk
na ratunek przy użyciu znaczników otaczających, aby zdefiniować ograniczniki rekordów
$ awk -v RS="</?repositories-item>" "/<type>hosted</type>/" file
<name>hosted-npm</name>
<type>hosted</type>
Zauważ, że wymaga to wielu znaków RS, które GNU awk
obsługuje.
możesz mieć większą kontrolę nad dopasowaniem i wyjściem
$ awk -v RS="</?repositories-item>" -F"[<>]" "
{delete a;
for(i=2;i<=NF;i+=4) a[$i]=$(i+1);
if(a["type"]=="hosted") print a["name"] }" file
hosted-npm