2016-07-19 19 views
1

Ich habe eine XML-Datei wie:xmlstarlet: Abfragen und verschachtelte untergeordnete Elemente mit einer einzigen Abfrage verketten

<?xml version="1.0" encoding="utf-8"?> 
<project> 
<data> 
    <modelType type="InstantMessage"> 
     <model type="InstantMessage" id="1" > 
      <modelField name="From" type="Party"> 
       <model type="Party" id="123456"> 
        <field name="Identifier" type="String"> 
         <value type="String">foo</value> 
        </field> 
       </model> 
      </modelField> 
      <multiModelField name="To" type="Party" /> 
       <field name="Body" type="String"> 
        <value type="String">bar</value> 
       </field> 
       <field name="TimeStamp" type="TimeStamp"> 
        <value type="TimeStamp">2016-07-11 13:26:38+02:00</value> 
       </field> 
     </model> 
    </modelType> 
</data> 

ich mit einer einzigen Abfrage folgendem Ergebnis erzeugen will:

foo|bar 

Ich weiß nicht, wie Sie auf diese Felder zugreifen, wenn sie in verschiedenen Ebenen verschachtelt sind. Ich habe versucht, etwas wie:

[email protected]:/.../# xmlstarlet sel -T -t -m /project/data/modelType/model -v "concat(/modelField/model/field/value'|'/field[@Body]/value)" file.xml 

, aber ich habe permanent Syntaxfehler von Xmlstarlet. Ich verstehe nicht, wie man es von der manual verwendet. Kann jemand in diesem Fall xmlstarlet verwenden?

Danke, Peter

Antwort

2

Ihre XML-Datei (wie dargestellt) wird einen engen Tag für <project> fehlt; Das wird einen Parsing-Fehler verursachen, der verhindern wird, dass xmlstarlet die Abfrage ausführen kann.

Die Abfrage selbst hat ein paar Probleme: in

  1. Die Syntax für die concat-Funktion ist concat(a,b,c); Deine Invokation lässt die Kommas weg.

  2. Innerhalb einer Übereinstimmung sind xpaths relativ zum übereinstimmenden Knoten. Aber das erste Element in der concat:

    ist absolut, so kann es nur von der Wurzel übereinstimmen, was es nicht tut. Sie benötigen einen relativ Ausdruck:

    modelField/model/field/value 
    

    oder

    ./modelField/model/field/value 
    

    Und die letzte XPath:

    /field[@Body]/value 
    

    nicht gefunden werden, weil field nicht das Wurzelelement ist, und ohne die / es wird auch nicht übereinstimmen, da field kein direktes Kind des übereinstimmenden Knotens ist. Hier können Sie entweder buchstabieren den Pfad von dem angepassten Knoten, wie oben, oder verwenden Sie // jedes Kind zu wählen:

    .//field[@Body]/value 
    
  3. jedoch der Spezifizierer [@Body] falsch ist. Wie beschrieben, ist der Selektor erfolgreich, wenn das Element ein Attribut mit dem Namen Body hat. Sie versuchen, ein Element mit einem Attribut mit dem Namen name abzugleichen, dessen Wert Body lautet und den Sie als [@name="Body"] schreiben würden. Die Anführungszeichen sind obligatorisch, was bedeutet, dass Sie einfache Anführungszeichen um den Ausdruck oder Backslash-Escape-Anführungszeichen verwenden müssen.

Putting, dass alle zusammen, sobald Sie die XML-Datei zu beheben könnten Sie verwenden:

xmlstarlet sel -T \ 
    -t -m /project/data/modelType/model \ 
    -v 'concat(modelField/model/field/value,"|",.//field[@name="Body"]/value)' \ 
    file.xml 

Der concat Anruf nicht wirklich notwendig ist, da Sie mehr -v Optionen verwenden können, und -o zur Ausgabe eines festen Zeichenfolge. Sie könnten die folgenden besser lesbar finden:

xmlstarlet sel -T \ 
    -t -m '/project/data/modelType/model' \ 
    -v './/field[@name="Identifier"]/value' \ 
    -o '|' \ 
    -v './/field[@name="Body"]/value' \ 
    file.xml 
+0

Große Erklärung !! – user3586330

+0

Das ist so eine tolle Antwort! Die einzige Sache ist, gibt es 2 fehlende Anführungszeichen nach '-m' und' [@ name = "Bezeichner"]/Wert' hier ist es mit den Anführungszeichen hinzugefügt 'xmlstarlet sel-T \ -t -m '/ project/data/modelType/model '\ -v' .//field[@name="Identifier"]/value '\ -o' | ' \ -v './/field[@name="Body"]/value' \ file.xml' – jarisky

+0

@jarisky: Danke für das Korrekturlesen. Fest. – rici