@@ -9,31 +9,43 @@ use walkdir::WalkDir;
99
1010use crate :: zip_util:: ZipUtil ;
1111
12+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
13+ enum Mode {
14+ Attribute ,
15+ Value
16+ }
17+
1218pub struct XMLUtil {
1319}
1420
1521impl XMLUtil {
1622 pub fn cat ( dir : & str , src_file : & str ) {
17- Self :: snr_xml ( dir, src_file, None , None , None , None ) ;
23+ Self :: snr_xml ( Mode :: Value , dir, src_file, None , None , None , None ) ;
1824 }
1925
2026 pub fn grep_xml ( dir : & str , src_file : & str , pattern : & str ) {
21- Self :: snr_xml ( dir, src_file, None , Some ( pattern) , None , None ) ;
27+ Self :: snr_xml ( Mode :: Value , dir, src_file, None , Some ( pattern) , None , None ) ;
2228 }
2329
2430 pub fn replace_xml ( dir : & str , src_file : & str , pattern : & str , replace : & str , output_file : & Option < String > ) {
25- let out_file;
31+ let out_file = match output_file {
32+ Some ( of) => of. as_str ( ) ,
33+ None => src_file
34+ } ;
2635
27- if let Some ( of) = output_file {
28- out_file = of. as_str ( ) ;
29- } else {
30- out_file = src_file;
31- }
36+ Self :: snr_xml ( Mode :: Value , dir, src_file, Some ( vec ! ( "word/document.xml" ) ) , Some ( pattern) , Some ( replace) , Some ( out_file) ) ;
37+ }
38+
39+ pub fn replace_attr ( dir : & str , src_file : & str , pattern : & str , replace : & str , output_file : & Option < String > ) {
40+ let out_file = match output_file {
41+ Some ( of) => of. as_str ( ) ,
42+ None => src_file
43+ } ;
3244
33- Self :: snr_xml ( dir, src_file, Some ( vec ! ( "word/document.xml" . to_string ( ) ) ) , Some ( pattern) , Some ( replace) , Some ( out_file) ) ;
45+ Self :: snr_xml ( Mode :: Attribute , dir, src_file, Some ( vec ! ( "word/_rels/ document.xml.rels" ) ) , Some ( pattern) , Some ( replace) , Some ( out_file) ) ;
3446 }
3547
36- fn snr_xml ( dir : & str , src_file : & str , files : Option < Vec < String > > , pattern : Option < & str > , replace : Option < & str > , output_file : Option < & str > ) {
48+ fn snr_xml ( mode : Mode , dir : & str , src_file : & str , files : Option < Vec < & str > > , pattern : Option < & str > , replace : Option < & str > , output_file : Option < & str > ) {
3749 let mut base_dir = dir. to_owned ( ) ;
3850 if !dir. ends_with ( "/" ) {
3951 base_dir. push ( '/' ) ;
@@ -47,16 +59,20 @@ impl XMLUtil {
4759 }
4860
4961 for entry in WalkDir :: new ( dir) . into_iter ( ) . filter_map ( |e| e. ok ( ) ) {
50- if entry. file_type ( ) . is_file ( ) && entry . file_name ( ) . to_string_lossy ( ) . ends_with ( ".xml" ) {
62+ if entry. file_type ( ) . is_file ( ) {
5163 let sub_path = Self :: get_sub_path ( entry. path ( ) , & base_dir) ;
5264
5365 if let Some ( file_list) = & files {
54- if !file_list. contains ( & sub_path) {
66+ if !file_list. contains ( & sub_path. as_str ( ) ) {
67+ continue ;
68+ }
69+ } else {
70+ if !( sub_path. ends_with ( ".xml" ) ) {
5571 continue ;
5672 }
5773 }
5874
59- Self :: snr_xml_file ( entry. path ( ) , & regex, & replace, & base_dir , src_file) ;
75+ Self :: snr_xml_file ( mode , entry. path ( ) , & regex, & replace, src_file) ;
6076 }
6177 }
6278
@@ -65,7 +81,7 @@ impl XMLUtil {
6581 }
6682 }
6783
68- fn snr_xml_file ( path : & Path , regex : & Option < Regex > , replace : & Option < & str > , base_dir : & str , src_file : & str ) {
84+ fn snr_xml_file ( mode : Mode , path : & Path , regex : & Option < Regex > , replace : & Option < & str > , src_file : & str ) {
6985 // detect BOM (Byte Order Mark)
7086 let bom = Self :: get_bom ( path) ;
7187 let f = File :: open ( path) . unwrap ( ) ; // TODO
@@ -82,20 +98,63 @@ impl XMLUtil {
8298
8399 match dom_res {
84100 Ok ( dom) => {
85- if Self :: snr_xml_node ( & dom, regex, replace, path, base_dir, src_file) {
101+ let changed = match mode {
102+ Mode :: Attribute =>
103+ Self :: snr_xml_attribute ( & dom, regex, replace, src_file) ,
104+ Mode :: Value =>
105+ Self :: snr_xml_node ( & dom, regex, replace, src_file)
106+ } ;
107+
108+ if changed {
86109 std:: fs:: write ( path, dom. to_string ( ) ) . unwrap ( ) ;
87110 }
88111 } ,
89112 Err ( e) => println ! ( "Problem with XML file {}: {}" , path. display( ) , e)
90113 }
91114 }
92115
93- fn snr_xml_node ( node : & RefNode , regex : & Option < Regex > , replace : & Option < & str > , path : & Path , base_dir : & str , src_file : & str )
116+ fn snr_xml_attribute ( node : & RefNode , regex : & Option < Regex > , replace : & Option < & str > , src_file : & str )
117+ -> bool {
118+ let mut changed = false ;
119+
120+ for n in node. child_nodes ( ) {
121+ for ( _, mut attr) in n. attributes ( ) {
122+ // let v = av.value();
123+ // println!("Name: {} = {:?}", an, v);
124+ if let Some ( v) = attr. value ( ) {
125+ if v. len ( ) == 0 {
126+ continue ;
127+ }
128+
129+ match regex {
130+ Some ( r) => {
131+ if r. is_match ( & v) {
132+ println ! ( "{}: {}={}" , src_file, attr. node_name( ) , v) ;
133+ if let Some ( repl) = replace {
134+ let res = r. replace_all ( & v, * repl) ;
135+ let _ = attr. set_value ( & res) ;
136+ changed = true ;
137+ }
138+ }
139+ } ,
140+ None => {
141+ println ! ( "{}: {}={}" , src_file, attr. node_name( ) , v) ;
142+ }
143+ }
144+ }
145+ }
146+ changed |= Self :: snr_xml_attribute ( & n, regex, replace, src_file) ;
147+ }
148+
149+ changed
150+ }
151+
152+ fn snr_xml_node ( node : & RefNode , regex : & Option < Regex > , replace : & Option < & str > , src_file : & str )
94153 -> bool {
95154 let mut changed = false ;
96155
97156 for mut n in node. child_nodes ( ) {
98- if let Option :: Some ( v) = n. node_value ( ) {
157+ if let Some ( v) = n. node_value ( ) {
99158 if v. len ( ) == 0 {
100159 continue ;
101160 }
@@ -116,7 +175,7 @@ impl XMLUtil {
116175 }
117176 }
118177 }
119- changed |= Self :: snr_xml_node ( & n, regex, replace, path , base_dir , src_file) ;
178+ changed |= Self :: snr_xml_node ( & n, regex, replace, src_file) ;
120179 }
121180
122181 changed
0 commit comments