2017-12-27 7 views
1

Haben Sie sich gefragt, ob es möglich wäre, ein einfaches Skript zu machen, um zu prüfen, ob mehrere Kriterien erfüllt sind und notwendige Änderungen an der Datei vorzunehmen.Suchen Sie mehrere Zeilen in TXT/XML-Datei und entfernen Sie, wenn Kriterien erfüllt

Weiter zum Beispiel von dem, was ich habe und was ich erreichen möchte.

Ich habe eine XML-Datei mit 4 Zeilen - Nummer, Jahr, Modell und Mann.

Wenn <man> ist Ford oder Dodge, möchte ich keine Änderungen vorgenommen werden. Aber wenn <man> ist etwas anderes als das, dann möchte ich überprüfen, ob <year> oder <model> sind "NA" und entfernen Sie die Zeile mit "NA".

<?xml version="1.0" encoding="UTF-8"?> 
<CarStuff> 
    <fileName>CarExpor201217.xml</fileName> 
    <numberCars>5</numberCars> 
    <ref>2017XY</ref> 
    <carExo id="CAR0001_01"> 
     <dealVen id="CAR0001_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0001_03"> 
      <amount>1811.10</amount> 
      <lotNumber>1</lotNumber> 
      <year>NA</year>    - Line must be removed 
      <model>NA</model>   - Line must be removed 
      <man>Acura</man> 
     </soldCar> 
    </carExo> 
    <carExo id="CAR0002_01"> 
     <dealVen id="CAR0002_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0002_03"> 
      <amount>1811.10</amount> 
      <lotNumber>1</lotNumber> 
      <year>NA</year>   - Line must be kept 
      <model>NA</model>  - Line must be kept 
      <man>Ford</man> 
     </soldCar> 
    </carExo> 
    <carExo id="CAR0003_01"> 
     <dealVen id="CAR0003_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0003_03"> 
      <amount>1811.10</amount> 
      <lotNumber>1</lotNumber> 
      <year>1997</year>  - Line must be kept 
      <model>NA</model>  - Line must be removed 
      <man>Bugati</man> 
     </soldCar> 
    </carExo> 
    <carExo id="CAR0004_01"> 
     <dealVen id="CAR0004_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0004_03"> 
      <amount>1811.10</amount> 
      <lotNumber>1</lotNumber> 
      <year>1997</year>  - Line must be kept 
      <model>NA</model>  - Line must be kept 
      <man>Dodge</man> 
     </soldCar> 
    </carExo> 
    <carExo id="CAR0005_01"> 
     <dealVen id="CAR0005_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0005_03"> 
      <amount>1811.10</amount> 
      <lotNumber>2</lotNumber> 
      <year>NA</year>   - Line must be kept 
      <model>Charger</model> - Line must be kept 
      <man>Dodge</man> 
     </soldCar> 
    </carExo> 
    <carExo id="CAR0005_01"> 
     <dealVen id="CAR0005_02"> 
      <name>John</name> 
      <surname>Smith</surname> 
     </dealVen> 
     <soldCar id="CAR0005_03"> 
      <amount>1811.10</amount> 
      <lotNumber>3</lotNumber> 
      <year>NA</year>   - Line must be removed 
      <model>Dot</model>  - Line must be kept 
      <man>Datsun</man> 
     </soldCar> 
    </carExo> 
</CarStuff> 

Dankbar für alle Kommentare und Ideen.

+0

Editiertes/korrigiertes falsches schließendes Tag '' an '', um eine wohlgeformte XML-Datei zu erhalten. –

Antwort

0

Lösung über XMLDOM

Sie XMLDOM und XPath können in einem so genannten NodeList für <man> Tags nicht enthält, Ausweichen oder Ford-Strings und überprüfen Sie alle Geschwister suchen, wenn sie „NA“ enthalten, um zu löschen Sie. Der folgende Code verwendet späte Bindung. BTW, Ihre XML in OP war nicht gut gebildet (schließendes Tag </carStuf> anstelle von </carStuff> - Ich fügte eine kleine Parsefehlerroutine hinzu, um diese beim Laden zu überprüfen.

-Code

Option Explicit 

Sub checkNA() 
Dim xDoc  As Object ' xml document 
Dim noli, noli2 As Object ' node list 
Dim no, no2  As Object ' node 
Dim noMan  As Object ' node <man> to check if no Dodge or Ford 
Dim s   As String 
Dim sFile  As String ' xml file name 

    sFile = ThisWorkbook.Path & "\xml\na_test.xml" ' <<< change to your xml file name 

' late binding xml 
    Set xDoc = CreateObject("MSXML2.DOMDocument.6.0") 
    xDoc.async = False: xDoc.validateOnParse = False 
    xDoc.setProperty "SelectionLanguage", "XPath" 
' load xml 
    If xDoc.Load(sFile) Then 
    Debug.Print "Loaded successfully" 
    Else 
    Dim xPE  As Object ' Set xPE = CreateObject("MSXML2.IXMLDOMParseError") 
    Dim strErrText As String 
    Set xPE = xDoc.parseError 
    With xPE 
    strErrText = "Load error " & .ErrorCode & " xml file " & vbCrLf & _ 
       Replace(.URL, "file:///", "") & vbCrLf & vbCrLf & _ 
       xPE.reason & _ 
       "Source Text: " & .srcText & vbCrLf & vbCrLf & _ 
       "Line No.: " & .Line & vbCrLf & _ 
       "Line Pos.: " & .linepos & vbCrLf & _ 
       "File Pos.: " & .filepos & vbCrLf & vbCrLf 
    End With 
    MsgBox strErrText, vbExclamation 
    Set xPE = Nothing 
    Exit Sub 
    End If 

' check items 
    s = "carExo/soldCar" 
    Set noli = xDoc.DocumentElement.SelectNodes(s) 
    For Each no In noli 
     Set noMan = no.SelectSingleNode("man") 
     If Not noMan Is Nothing Then 
     If InStr("Ford.Dodge" & ".", noMan.Text & ".") = 0 Then 
      Debug.Print "delete", noMan.Text 
      ' delete all subtags containing "NA" as text 
      Set noli2 = no.SelectNodes("*") 
      For Each no2 In noli2 
       If no2.Text = "NA" Then 
        ' delete item 
        Debug.Print , no2.nodename & "=" & no2.Text 
        no2.ParentNode.RemoveChild no2 
       End If 
      Next no2 

     Else 
      ' Debug.Print "keep", noman.Text 
     End If 
     End If 
    Next no 

' save 
    ' Debug.Print xDoc.XML 
    xDoc.Save sFile  
' close 
    Set xDoc = Nothing 
End Sub 

bearbeiten 12/29 - Nachtrag

habe ich eine zweite tragfähige Version des ' check items Teil einige zusätzliche XPath verwenden. Diese Alternative vermeidet einfach zwei If Bedingungen in normalem Code, da sie den Bereich gefundener Knoten in den zwei Knotenlisten einschränkt.

' check items 
    s = "carExo/soldCar[man!='Ford'][man!='Dodge']" ' << (1) added condition to XPath 
    Set noli = xDoc.DocumentElement.SelectNodes(s) 
    For Each no In noli 
     Set noMan = no.SelectSingleNode("man") 
     If Not noMan Is Nothing Then 
     Debug.Print "delete", noMan.Text 
     ' delete all subtags containing "NA" as text 
     Set noli2 = no.SelectNodes("*[.='NA']") ' << (2)added condition to XPath 
     For Each no2 In noli2 
      ' delete item 
      Debug.Print , no2.nodename & "=" & no2.Text 
      no2.ParentNode.RemoveChild no2 
     Next no2 
     End If 
    Next no 

Hint

Natürlich gibt es viele Straßen nach Rom führen, finden Sie @Parfait ‚s XSLT Ansatz unten.

+0

Großartig! Einfach und leicht zu verstehen. Ich muss nur leicht ändern, nur um Knoten, egal den Elternknoten zu finden. – user99776644

+1

Falls jemand es brauchen würde, vielleicht gibt es einen einfacheren Weg, aber tat es so: Set noli = xDoc.DocumentElement.SelectNodes ("abcendant :: soldCar") – user99776644

+0

Ich bin froh, dass ich hilfreich sein könnte. Ich habe meine Antwort mit einer zweiten praktikablen Version bearbeitet, die erlaubt, zwei 'If'-Bedingungen zu vermeiden, indem sie in die XPath-Zeichenkette aufgenommen werden. –

0

Klingt, als müssten Sie alle Zeilen entfernen, die >NA< enthalten.

Das ist nicht wirklich eine Programmiersprache Frage ist (so ist es off-topic), aber hier ist eine schnelle Antwort mit Notepad++:

  • Ctrl +H das finden Ersetzen-Dialog aufzurufen.

  • Im Find what: Textfeld umfassen Ihre regex: .*>NA<.*\r?\n (wo die \r im Fall optional ist die Datei nicht Windows-Zeilenende haben).

  • Lassen Sie das Textfeld Replace with: leer.

  • Stellen Sie sicher, dass das Optionsfeld Regular Expression im Suchmodusbereich ausgewählt ist.

  • lecken Replace All und voilà! Alle Zeilen, die >NA< enthalten, wurden entfernt.

NPP repl line example

(Antwort aus this angepasst).

+0

Ich wünschte, es wäre so einfach. Die Ford kann auch Linien mit NA haben, aber diese sollten beibehalten werden. Das ist der Grund, warum ich nach Feldern suche, wo NICHT Ford oder Ausweichen ist. Zusätzlich sollten nur zwei Zeilen über auf NA geprüft werden. – user99776644

+0

eine einmalige Sache? oder etwas, das wiederholt getan werden muss? – ashleedawg

+0

Es gibt eine Reihe von Möglichkeiten, dies zu lösen abhängig von ein paar Dinge wie, ob die Datei korrekt formatiert XML ist (im Gegensatz zu Ihrem Beispiel, fehlende Top-Level, etc), sowie woher diese Datei kommt, ob dies ist eine 1-fache Änderung, wo die Daten gehen, wenn Sie fertig sind, usw. – ashleedawg

1

Verwenden Sie einfach XSLT, die spezielle Sprache, die entwickelt wurde, um genau das zu tun, was Sie bei der Umwandlung der ursprünglichen XML-Datei benötigen, indem Knoten nach verschiedenen Kriterien entfernt werden.

Insbesondere unten läuft die Identity Transform, XML zu kopieren, wie es ist und schließt dann die Knoten nach Ihren Kriterien für Modell/Jahr/Mann aus.

XSLT(als .xsl speichern, eine spezielle XML-Datei)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="soldCar[man != 'Ford' and man != 'Dodge']"> 
    <xsl:copy> 
     <xsl:copy-of select="amount|lotNumber"/> 
     <xsl:if test="model != 'NA'"> 
      <xsl:copy-of select="model"/> 
     </xsl:if> 
     <xsl:if test="year != 'NA'"> 
      <xsl:copy-of select="year"/> 
     </xsl:if> 
     <xsl:copy-of select="man"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

VBA

Public Sub RunXSLT() 
    Dim strFile As String, strPath As String 
    ' REFERENCE MS XML, v6.0 
    Dim xmlDoc As New MSXML2.DOMDocument60, xslDoc As New MSXML2.DOMDocument60 
    Dim newDoc As New MSXML2.DOMDocument60 

    ' LOAD XML SOURCE 
    xmlDoc.Load "C:\Path\To\Input.xml" 

    ' LOAD XSL SOURCE 
    xslDoc.Load "C:\Path\To\XSLT\Script.xsl" 

    ' TRANSFORM SOURCE 
    xmlDoc.transformNodeToObject xslDoc, newDoc 
    newDoc.Save "C:\Path\To\Output.xml" 

    ' RELEASE DOM OBJECTS 
    Set xmlDoc = Nothing: Set xslDoc = Nothing: Set newDoc = Nothing 
End Sub 

Ausgabe

<?xml version="1.0" encoding="utf-8"?> 
<CarStuff> 
    <fileName>CarExpor201217.xml</fileName> 
    <numberCars>5</numberCars> 
    <ref>2017XY</ref> 
    <carExo id="CAR0001_01"> 
    <dealVen id="CAR0001_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar> 
     <amount>1811.10</amount> 
     <lotNumber>1</lotNumber> 
     <man>Acura</man> 
    </soldCar> 
    </carExo> 
    <carExo id="CAR0002_01"> 
    <dealVen id="CAR0002_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar id="CAR0002_03"> 
     <amount>1811.10</amount> 
     <lotNumber>1</lotNumber> 
     <year>NA</year> 
     <model>NA</model> 
     <man>Ford</man> 
    </soldCar> 
    </carExo> 
    <carExo id="CAR0003_01"> 
    <dealVen id="CAR0003_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar> 
     <amount>1811.10</amount> 
     <lotNumber>1</lotNumber> 
     <year>1997</year> 
     <man>Bugati</man> 
    </soldCar> 
    </carExo> 
    <carExo id="CAR0004_01"> 
    <dealVen id="CAR0004_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar id="CAR0004_03"> 
     <amount>1811.10</amount> 
     <lotNumber>1</lotNumber> 
     <year>1997</year> 
     <model>NA</model> 
     <man>Dodge</man> 
    </soldCar> 
    </carExo> 
    <carExo id="CAR0005_01"> 
    <dealVen id="CAR0005_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar id="CAR0005_03"> 
     <amount>1811.10</amount> 
     <lotNumber>2</lotNumber> 
     <year>NA</year> 
     <model>Charger</model> 
     <man>Dodge</man> 
    </soldCar> 
    </carExo> 
    <carExo id="CAR0005_01"> 
    <dealVen id="CAR0005_02"> 
     <name>John</name> 
     <surname>Smith</surname> 
    </dealVen> 
    <soldCar> 
     <amount>1811.10</amount> 
     <lotNumber>3</lotNumber> 
     <model>Dot</model> 
     <man>Datsun</man> 
    </soldCar> 
    </carExo> 
</CarStuff> 
+0

Hilfreich, da es umgekehrt über XSLT (und frühe Bindung) + –

+0

In der Tat zeigt. Und noch mehr XSLT ist tragbar und nicht auf VBA beschränkt. OP kann das gleiche XSL-Skript in anderen Sprachen verwenden, um Original-XML zu transformieren: Java, PHP, Python, sogar PowerShell und Bash! Keine 'For'-Schleifen oder' If ... Then'-Logik benötigt. – Parfait

Verwandte Themen