การสคริปต์: วิธีที่ง่ายที่สุดในการแยกค่าในแท็กของไฟล์ XML คืออะไร


14

ฉันต้องการอ่าน pom.xml ('Project Object Model' ของ Maven) และแยกข้อมูลรุ่น นี่คือตัวอย่าง:

<?xml version="1.0" encoding="UTF-8"?><project 
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>project-parent</artifactId>
    <name>project-parent</name>
    <version>1.0.74-SNAPSHOT</version>
    <dependencies>
        <dependency>
        <groupId>com.sybase.jconnect</groupId>
        <artifactId>jconnect</artifactId>
        <version>6.05-26023</version>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jdmk</groupId>
        <artifactId>jmxtools</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>2.4</version>
    </dependency>       
</dependencies>
</project>

ฉันจะแยกเวอร์ชัน '1.0.74-SNAPSHOT' จากด้านบนได้อย่างไร

ชอบที่จะสามารถทำได้โดยใช้สคริปต์ทุบตีเรียบง่ายหรือ awk มิฉะนั้นจะแนะนำให้ใช้ไพ ธ อนธรรมดา

แก้ไข

  1. การ จำกัด

    กล่อง linux อยู่ในสภาพแวดล้อมขององค์กรดังนั้นฉันสามารถใช้เครื่องมือที่ติดตั้งไว้แล้วเท่านั้น (ไม่ใช่ว่าฉันไม่สามารถขอยูทิลิตี้เช่น xml2 แต่ฉันต้องผ่านเทปสีแดงจำนวนมาก) วิธีแก้ปัญหาบางอย่างนั้นดีมาก (เรียนรู้เคล็ดลับใหม่แล้ว) แต่อาจไม่สามารถใช้งานได้เนื่องจากสภาพแวดล้อมที่ จำกัด

  2. อัปเดตรายการ xml แล้ว

    ฉันเพิ่มแท็กการอ้างอิงในรายชื่อเดิม วิธีนี้จะแสดงวิธีการแฮ็กบางอย่างอาจไม่ทำงานในกรณีนี้

  3. distro

    distro ที่ฉันใช้คือ RHEL4


stackoverflow.com/questions/29004/…นี้เพียงพอหรือไม่
bbaja42

ไม่ได้จริงๆ มีแท็กเวอร์ชันจำนวนมากใน xml (เช่นภายใต้แท็กการพึ่งพา) ฉันต้องการเฉพาะ '/ project / version'
Anthony Kong

มีเครื่องมือและไลบรารีที่เกี่ยวข้องกับ xml ใดบ้าง solvuions ที่ใช้ jvm ตกลงหรือไม่
วิ

จนถึงตอนนี้ฉันสามารถบอกได้ว่าไม่มีโมดูล xml2, xmlgrep และ perl XML ยูทิลิตีบรรทัดคำสั่ง unix ส่วนใหญ่มีอยู่ Distro คือ Redhat EL 4
Anthony Kong

(ฉันไม่สามารถเพิ่มความคิดเห็นดังนั้นฉันต้องตอบเป็นคำตอบ overkill บ้าง) คำตอบที่ดีบางอย่างสามารถพบได้ที่นี่ ..... stackoverflow.com/questions/2735548/…
JStrahl

คำตอบ:


17

xml2 สามารถแปลง xml เป็น / จากรูปแบบที่เน้นบรรทัด:

xml2 < pom.xml  | grep /project/version= | sed 's/.*=//'

6

วิธีอื่น ๆ : xmlgrep และ XPath:

xmlgrep --text_only '/project/version' pom.xml

ข้อเสีย: ช้า


คำสั่งอัปเดตเป็นxml_grep
GAD3R

6

การใช้ python

$ python -c 'from xml.etree.ElementTree import ElementTree; print ElementTree(file="pom.xml").findtext("{http://maven.apache.org/POM/4.0.0}version")'
1.0.74-SNAPSHOT

การใช้ xmlstarlet

$ xml sel -N x="http://maven.apache.org/POM/4.0.0" -t -m 'x:project/x:version' -v . pom.xml
1.0.74-SNAPSHOT

การใช้ xmllint

$ echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:version/text()' | xmllint --shell pom.xml | grep -v /
1.0.74-SNAPSHOT

cat (//x:version)[1]/text()เมื่อใช้xmllintงานยังใช้งานได้!
kev

5

วิธี Clojure ต้องการเฉพาะ jvm พร้อมไฟล์ jar พิเศษ:

java -cp clojure.jar clojure.main -e "(use 'clojure.xml) (->> (java.io.File. \"pom.xml\") (clojure.xml/parse) (:content) (filter #(= (:tag %) :version)) (first) (:content) (first) (println))"

วิธีสกาล่า:

java -Xbootclasspath/a:scala-library.jar -cp scala-compiler.jar scala.tools.nsc.MainGenericRunner -e 'import scala.xml._; println((XML.load(new java.io.FileInputStream("pom.xml")) match { case <project>{children @ _*}</project> => for (i <- children if (i  match { case <version>{children @ _*}</version> => true; case _ => false;  }))  yield i })(0) match { case <version>{Text(x)}</version> => x })'

วิธี Groovy:

java -classpath groovy-all.jar groovy.ui.GroovyMain -e 'println (new XmlParser().parse(new File("pom.xml")).value().findAll({ it.name().getLocalPart()=="version" }).first().value().first())'

นี่มันเจ๋งมาก! ความคิดที่ดี!
Anthony Kong

4

นี่คือทางเลือกใน Perl

$ perl -MXML::Simple -e'print XMLin("pom.xml")->{version}."\n"'
1.0.74-SNAPSHOT

มันทำงานร่วมกับตัวอย่างแก้ไข / ขยายในคำถามที่มีองค์ประกอบ "รุ่น" หลายที่ระดับความลึกที่แตกต่างกัน


ช้า (แม้ว่าจะเร็วกว่า xmlgrep)
Vi

3

วิธีแฮ็ค :

perl -e '$_ = join "", <>; m!<project[^>]*>.*\n(?:    |\t)<version[^>]*>\s*([^<]+?)\s*</version>.*</project>!s and print "$1\n"' pom.xml

อาศัยการเยื้องที่ถูกต้องของสิ่งที่ต้องการ <version>


ขอบคุณสำหรับคำแนะนำ แต่น่าเสียดายที่มันจะไม่คืนสิ่งที่ฉันต้องการ โปรดดูรุ่น pom ที่อัพเดท
Anthony Kong

ส่งคืน "1.0.74-SNAPSHOT" โปรดทราบว่าฉันเปลี่ยนสคริปต์หลังจากอ่านเกี่ยวกับหลาย<version>สิ่ง
วิ

หมายเหตุ: โซลูชันนี้มีให้ "เพื่อความสนุก" และไม่ได้มีวัตถุประสงค์เพื่อใช้ในผลิตภัณฑ์จริง ควรใช้ xml2 / xmlgrep / XML :: วิธีที่ง่ายกว่า
วิ

ขอบคุณ! ถึงแม้ว่ามันจะเป็น 'เพื่อความสนุก' แต่มันอาจเป็นทางออกที่ 'เหมาะสมที่สุด' ในตอนนี้เพราะมันมีจำนวนการพึ่งพาขั้นต่ำ: มันแค่ต้องการ perl ;-)
Anthony Kong

เกี่ยวกับการทำมันจาก Java? การใช้ไฟล์ pom แสดงถึงการติดตั้ง JVM
วิ

3

หาวิธีแก้ปัญหาที่ซับซุ่มซ่ามมาก

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [n for n in dom.getElementsByTagName('version') if n.parentNode == dom.childNodes[0]][0].toxml()" | sed -e "s/.*>\(.*\)<.*/\1/g"

ความใจเย็นในตอนท้ายนั้นดูน่าเกลียดมาก แต่ฉันก็ไม่สามารถพิมพ์ข้อความของปมด้วยความคิดเพียงอย่างเดียว

อัปเดตจาก _Vi :

Python เวอร์ชันแฮ็คน้อย

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [i.childNodes.item(0).nodeValue for i in dom.firstChild.childNodes if i.nodeName == 'version'].pop()"

อัปเดตจากฉัน

รุ่นอื่น:

    python -c "from  xml.dom.minidom import parse;dom = parse('pom.xml');print [n.firstChild.data for n in dom.childNodes[0].childNodes if n.firstChild and n.tagName == 'version']"

2

วิธี XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>

        <xsl:template match="/">
                <xsl:for-each select="*[local-name()='project']">
                    <xsl:for-each select="*[local-name()='version']">
                        <xsl:value-of select="text()"/>
                    </xsl:for-each>
                </xsl:for-each>
        </xsl:template>
</xsl:stylesheet>
xalan -xsl x.xsl -in pom.xml

หาก xsltproc อยู่ในระบบของคุณและอาจเป็นเช่นเดียวกับ libxslt บน RHEL4 คุณสามารถใช้และสไตล์ชีทด้านบนเพื่อส่งออกแท็กเช่น xsltproc x.xsl prom.xsl
fpmurphy

2

หาก "มีแท็กเวอร์ชันจำนวนมากใน xml" คุณควรลืมทำด้วย "เครื่องมือง่าย ๆ " และ regexps ซึ่งจะไม่ทำเช่นนั้น

ลองใช้ไพ ธ อนนี้ (ไม่มีการขึ้นต่อกัน):

from xml.dom.minidom import parse

dom = parse('pom.xml')
project = dom.getElementsByTagName('project')[0]
for node in project.childNodes:
    if node.nodeType == node.ELEMENT_NODE and node.tagName == 'version':
        print node.firstChild.nodeValue

สคริปต์นี้ทำอะไรกันแน่
Simon Sheehan

มันโหลด XML เป็นโครงสร้าง DOM โดยใช้การดำเนินการ minidom ของ Python: docs.python.org/library/xml.dom.minidom.htmlแนวคิดก็คือการคว้าแท็ก <project> ที่ไม่ซ้ำใครและย้ำผ่านโหนดลูกของมัน (โดยตรง childs only) เพื่อค้นหาแท็ก <version> ที่เรากำลังค้นหาไม่ใช่แท็กอื่นที่มีชื่อเดียวกันในที่อื่น
Samus_

1

นี่คือหนึ่งซับโดยใช้ sed:

sed '/<dependencies>/,/<\/dependencies>/d;/<version>/!d;s/ *<\/\?version> *//g' pom.xml

1
อาศัยการไม่มีพารามิเตอร์ในองค์ประกอบและส่วนเสริม<version>นั้นสามารถอยู่ในการอ้างอิงเท่านั้น
วิ

1

awkทำงานได้ดีโดยไม่ต้องใช้เครื่องมือพิเศษใด ๆ
cat pod.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.networks.app</groupId>
  <artifactId>operation-platform</artifactId>
  <version>1.0.0</version>
  <packaging>tar.xz</packaging>
  <description>POM was created by Sonatype Nexus</description>
</project>

วิธีที่ง่ายและชัดเจนในการรับค่าของ<packaging>แท็ก:

cat pod.xml | awk -F'[<>]' '/packaging/{print $3}'

1
สิ่งนี้ดูเหมือนว่าจะใช้งานได้ แต่ระวัง: สิ่งที่มันถูกตั้งค่าตัวคั่นฟิลด์ (FS) เป็นชุดของตัวละคร <และ>; จากนั้นจะพบทุกบรรทัดที่มีคำว่า "บรรจุภัณฑ์" ในบรรทัดนั้นและให้ฟิลด์ที่สามแก่คุณ
SMerrill8


0

ฉันรู้ว่าคำถามของคุณบอกว่า Linux แต่ถ้าคุณมีความต้องการที่จะทำสิ่งนี้บน Windows โดยไม่ต้องใช้เครื่องมือของบุคคลที่สามซึ่งคุณสามารถใส่ไว้ในแฟ้มแบตช์ Powershell สามารถแยกโหนดใด ๆ จากไฟล์ pom.xml ของคุณเช่นนี้ :

powershell -Command "& {select-xml //pom:project/pom:properties/pom:mypluginversion -path pom.xml -Namespace  @{pom='http://maven.apache.org/POM/4.0.0'} | foreach {$_.Node.Innerxml}}" > myPluginVersion.txt

Powershell ตอนนี้เป็นโอเพ่นซอร์สและทำงานบน Linux และแพลตฟอร์มอื่น ๆ เราใช้มันในการสร้างตามความต้องการของ bash, cygwin และ ming64
Charlweed

0
sed -n "/<name>project-parent/{n;s/.*>\(.*\)<.*/\1/p;q}" pom.xml

-nตัวเลือกที่จะหลีกเลี่ยงการพิมพ์เส้นไม่ตรง; การจับคู่แรก ( /.../) อยู่ในบรรทัดก่อนหน้าการแข่งขันที่มีข้อความที่ต้องการ nคำสั่งข้ามไปยังบรรทัดถัดซึ่งsสารสกัดจากข้อมูลที่เกี่ยวข้องผ่านกลุ่มจับ ( \(...\)) และ backreference (ที่\1) pพิมพ์ออกqลาออก


2
คุณสามารถขยายคำตอบเพื่ออธิบายสิ่งนี้ได้หรือไม่? ขอบคุณ
fixer1234
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.