xml 是否可以通过某种方式进行编辑?

xml editing is it possible somehow?

我不确定是否可以完成以下任务。我已经完成了它的第一部分,所以我在这里放了一些我想进一步使用的代码。这个问题可能有点长,抱歉。我想编辑一个 xml 文件,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<notes version="1">
    <labels>
        <label id="0" color="80FF80">BadReg</label>
        <label id="1" color="FFFF40">GoodReg</label>
        <label id="2" color="8000FF">Bluffer</label>
        <label id="3" color="10FF10">Fish</label>
        <label id="4" color="1080FF">Loose</label>
        <label id="5" color="30DBFF">Semi-Loose</label>
        <label id="6" color="0000FF">Nit</label>
        <label id="7" color="FF9F48">Tight</label>
        <label id="8" color="C0C0C0">Undefined</label>
    </labels>
    <note player="00aquitis00" label="7" update="1429834930"></note>
    <note player="01 LUGAR" label="8" update="1429834930"></note>
    <note player="07 Star 07" label="4" update="1429834930"></note>
    <note player="109185" label="6" update="1429834930">Some notes are here</note>
    <note player="1111167" label="8" update="1429834930">And some there...</note>
</notes>

我想在上面的 *.xml 文件中编辑某些玩家的 ID 和他们的标签编号。首先我有一个 players.txt 和一个 ReportExport.csv 文件,它们看起来像这样,CSV:

"","Player","VPIP","PFR","Hands","Players"
"2532|100|""Seikei""&5RS","""Seikei""&5RS","20.45","12.50","88","5.65"
"4265|100|#23Mattingly","#23Mattingly","41.94","25.81","33","5.55"
"2748|100|#PachnacyBak","#PachnacyBak","11.54","10.00","52","5.44"
"6|100|eagle189","eagle189","20.60","13.60","73,561","5.55"

TXT:

player1         badreg
player2         badreg
player3         bluffer
player4         bluffer

第一步,我从 *.txt 和 *.csv 文件中获取数据(我想要使用的数据)。 AWK代码:

BEGIN   {
                update = 1429834930 }

FILENAME == "players.txt"   {

                FS = "\t\t"

                playertype = ;

                if (playertype == "badreg") {badregs[]++};
                if (playertype == "bluffer") {bluffers[]++};
                if (playertype == "fish") {fishes[]++};
                if (playertype == "goodreg") {goodregs[]++};
                next }

(FILENAME == "ReportExport.csv") && (FNR != 1)  {

                FS = "\",\""

                name = ;
                vpip = ;
                pfr = ;
                hands = ;
                avgp = substr(, 1, (length()-1));

                if (name == "") {name = "Name"}

                gsub(/&/, "\&amp;", name)
                gsub(/</, "\&lt;", name)
                gsub(/>/, "\&gt;", name)
                gsub(/\"\"\"/, "\"\"", name)
                gsub(/\"\"/, "\"", name)
                gsub(/\"/, "\&quot;", name)

                gsub(/,/, "", hands)

                label = 8;

                if ((hands >= 100) && ((vpip / 1.40) <= (100 / avgp))) {label = 7}  #Tight
                if ((hands >= 18) && ((vpip / 1.00) <= (100 / avgp))) {label = 7}   #Tight
                if ((hands >= 100) && ((vpip / 1.25) <= (100 / avgp))) {label = 6}  #Nit
                if ((hands >= 24) && ((vpip / 2.20) >= (100 / avgp))) {label = 5}   #Semi-Loose
                if ((hands >= 15) && ((vpip / 3.00) >= (100 / avgp))) {label = 4}   #Loose
                if ((hands >= 30) && ((vpip / 2.60) >= (100 / avgp))) {label = 4}   #Loose

                if ((hands >= 24) && ((vpip / 2.60) >= (100 / avgp)) && ((pfr/vpip) <= 0.2)) {label = 3}    #Fish

                if (name in fishes)     {label = 3} #Fish
                if (name in bluffers)   {label = 2} #Bluffer
                if (name in goodregs)   {label = 1} #GoodReg
                if (name in badregs)    {label = 0} #BadReg
            }

在这一点之后,当我终于得到了播放器的正确标签类型时,我想在 *.xml 文件中进行搜索,如果可以找到播放器,那么我'我想更新他的标签号,如果找不到他,我想在其他玩家旁边打印一行到 *.xml 文件中,如下所示:

printf("\t<note player=\"%s\" label=\"%s\" update=\"%s\"></note>\n", name, label, update)

然后保存*.xml文件,在处理csv文件时逐行重复此操作。在第一种情况下,如果可以找到播放器,重要的是不要替换 *.xml 文件中的整行,只需更新标签,因为有些播放器也可以包含一些注释(比如在示例代码),如果我们替换整行,它将丢失。所以真正的问题是,这些替换能否首先完成?如果可以的话,如果有人能告诉我应该从哪里继续,我将不胜感激:)当然,如果有更好的方法来代替逐行保存和搜索,我很想听听。

使用TXR的解决方案:

$ txr update.txr 
<?xml version="1.0" encoding="UTF-8"?>
<notes version="1">
    <labels>
        <label id="0" color="80FF80">BadReg</label>
        <label id="1" color="FFFF40">GoodReg</label>
        <label id="2" color="8000FF">Bluffer</label>
        <label id="3" color="10FF10">Fish</label>
        <label id="4" color="1080FF">Loose</label>
        <label id="5" color="30DBFF">Semi-Loose</label>
        <label id="6" color="0000FF">Nit</label>
        <label id="7" color="FF9F48">Tight</label>
        <label id="8" color="C0C0C0">Undefined</label>
    </labels>
    <note player="00aquitis00" label="7" update="1429834930"></note>
    <note player="01 LUGAR" label="8" update="1429834930"></note>
    <note player="07 Star 07" label="4" update="1429834930"></note>
    <note player="109185" label="7" update="1429834930">Some notes are here</note>
    <note player="1111167" label="8" update="1429834930">And some there...</note>
    <note player="&quot;Seikei&quot;&amp;5RS" label="0" update="1429834930"></note>
    <note player="#23Mattingly" label="5" update="1429834930"></note>
    <note player="#PachnacyBak" label="2" update="1429834930"></note>
    <note player="eagle189" label="6" update="1429834930"></note>
</notes>

update.txr中的代码:

@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;; Lisp struct and globals ;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@(do
   ;; Structure representing a player
   (defstruct player ()
     name label (update g-update) notes
     (vpip 0.0) (pfr 0.0) (hands 0) (avg 0.0)

     ;; post-construction hook
     (:postinit (self)
       ;; calculate label based on stats, if possible
       self.(calc-label)
       ;; If a player exists by the name, copy the properties to the old one
       ;; otherwise add the new one to the global list.
       (iflet ((old [name2player self.name]))
         old.(update-from self)
         self.(add))))

   ;; Add new player method
   (defmeth player add (self)
     (push self allplayers)
     (set [name2player self.name] self)
     (set g-update self.update))

   ;; Merge new player with existing entry
   (defmeth player update-from (old new)
     (set old.label (or new.label old.label))
     (set old.vpip (or new.vpip old.vpip))
     (set old.pfr (or new.pfr old.pfr))
     (set old.hands (or new.hands old.hands))
     (set old.avg (or new.avg old.avg)))

   ;; Method to calculate player's numeric label value.
   (defmeth player calc-label (p)
     (if (> p.avg 0.0)
       (let ((ravg (/ 100 p.avg)))
         (when (and (>= p.hands 100) (<= (/ p.vpip 1.40) ravg))
           (set p.label 7))
         (when (and (>= p.hands 18) (<= (/ p.vpip 1.00) ravg))
           (set p.label 7))
         (when (and (>= p.hands 100) (<= (/ p.vpip 1.25) ravg))
           (set p.label 6))
         (when (and (>= p.hands 24) (>= (/ p.vpip 2.20) ravg))
           (set p.label 5))
         (when (and (>= p.hands 15) (>= (/ p.vpip 3.00) ravg))
           (set p.label 4))
         (when (and (>= p.hands 30) (>= (/ p.vpip 2.60) ravg))
           (set p.label 4))

         (when (and (>= p.hands 24) (>= (/ p.vpip 2.60) ravg)
                    (> p.vpip 0.0) (<= (/ p.pfr p.vpip) 0.2))
           (set p.label 3)))))

   ;; Convert a player to XML.
   (defmeth player toxml (p)
      `<note player="@{p.name :filter :tohtml}" \
      \ label="@{p.label}" update="@{p.update}">@{p.notes}</note>`)

   ;; Global list of all player objects
   (defvarl allplayers nil)

   ;; Hash mapping player names to player objects.
   (defvarl name2player (hash :equal-based))

   ;; Global variable storing most recent player update value.
   (defvarl g-update)

   ;; Hash of lower-cased label type strings to ID strings.
   (defvarl type2label (hash :equal-based)))
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;; Process Notes.xml file               ;;
@;; - instantiates player objects        ;;
@;; - snarfs labels as labelxml list      ;;
@;; - populates type2label hash          ;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@(next "Notes.xml")
<?xml version="1.0" encoding="UTF-8"?>
<notes version="1">
    <labels>
@(collect :gap 0 :vars (labelxml))
@  (all)
@    labelxml
@  (and)
        <label id="@id" color="@co">@na</label>
@  (end)
@  (do (set [type2label (downcase-str na)] id))
@(end)
    </labels>
@(repeat :gap 0)
    <note player="@na" label="@l" update="@up">@nt</note>
@  (do (new player name na label l update up notes nt))
@(end)
</notes>
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;; Process ReportExport.csv file          ;;
@;; - just instantiates specified players  ;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@(next "ReportExport.csv")
"","Player","VPIP","PFR","Hands","Players"
@(repeat :gap 0)
"@junk","@na","@vpip","@pfr","@hands","@avg"
@  (do (new player
            name (regsub #/""/ "\"" na)   ;; handle "" -> " in name (CSV)
            vpip (tofloat vpip)
            pfr (tofloat pfr)
            hands (toint (remql #\, hands)) ;; nuke comma digit separator
            avg (tofloat avg)))
@(end)
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;; Process players.txt                    ;;
@;; - look up layer in name2player hash    ;;
@;; - look up label in type2label hash     ;;
@;; - if we have both, set player's label  ;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@(next "players.txt")
@(repeat)
@name @type
@  (do (let* ((pl [name2player name])
              (id [type2label (downcase-str type)]))
         (when (and pl id)
           (set pl.label id))))
@(end)
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;; Output updated XML                     ;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@(bind playerxml @(mapcar (umeth toxml) (nreverse allplayers)))
@(output)
<?xml version="1.0" encoding="UTF-8"?>
<notes version="1">
    <labels>
@  (repeat)
@       labelxml
@  (end)
    </labels>
@  (repeat)
    @playerxml
@  (end)
</notes>
@(end)

原始 Notes.xml 和输出之间的差异。在这里我们可以看到用户 109185 已更新,因为该用户已添加到 CSV。

$ diff -u Notes.xml <(txr update.txr)
--- Notes.xml   2015-12-21 16:04:51.790042327 -0800
+++ /dev/fd/63  2015-12-22 09:06:49.075320182 -0800
@@ -14,6 +14,10 @@
     <note player="00aquitis00" label="7" update="1429834930"></note>
     <note player="01 LUGAR" label="8" update="1429834930"></note>
     <note player="07 Star 07" label="4" update="1429834930"></note>
-    <note player="109185" label="6" update="1429834930">Some notes are here</note>
+    <note player="109185" label="7" update="1429834930">Some notes are here</note>
     <note player="1111167" label="8" update="1429834930">And some there...</note>
+    <note player="&quot;Seikei&quot;&amp;5RS" label="0" update="1429834930"></note>
+    <note player="#23Mattingly" label="5" update="1429834930"></note>
+    <note player="#PachnacyBak" label="2" update="1429834930"></note>
+    <note player="eagle189" label="6" update="1429834930"></note>
 </notes>

player.txt 的内容。请注意,这些用户在输出中被赋予了正确的标签,覆盖了根据他们的统计信息计算的标签。

#PachnacyBak    bluffer
"Seikei"&5RS    badreg

ReportExport.csv 的内容:

"","Player","VPIP","PFR","Hands","Players"
"2532|100|""Seikei""&5RS","""Seikei""&5RS","20.45","12.50","88","5.65"
"4265|100|#23Mattingly","#23Mattingly","41.94","25.81","33","5.55"
"2748|100|#PachnacyBak","#PachnacyBak","11.54","10.00","52","5.44"
"6|100|eagle189","eagle189","20.60","13.60","73,561","5.55"
"blah","109185","15.60","8.60","20","4.55"