-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create a tool to lowercase the xml tags
- Loading branch information
Showing
7 changed files
with
332 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
workshop/** | ||
!.gitkeep |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { | ||
std_fs, | ||
std_path, | ||
} from './deps.ts'; | ||
|
||
import {parse, serialize, Document as XMLDocument, Xml} from './xml.ts'; | ||
|
||
const {walk} = std_fs; | ||
const {extname} = std_path; | ||
|
||
class App { | ||
|
||
files: std_fs.WalkEntry[] = []; | ||
|
||
tagToLowerCase = (parent?: Xml) => { | ||
if (!parent) { | ||
return; | ||
} | ||
|
||
parent.name = parent.name.toLowerCase(); | ||
|
||
for (let child of parent.children) { | ||
this.tagToLowerCase(child); | ||
} | ||
}; | ||
|
||
markFiles = async () => { | ||
for await (const entry of walk("./workshop")) { | ||
if (entry.isFile && extname(entry.name) === ".xml") { | ||
|
||
this.files.push(entry); | ||
|
||
} | ||
} | ||
}; | ||
|
||
transform = async () => { | ||
|
||
for (let file of this.files) { | ||
let text: string = await Deno.readTextFile(file.path); | ||
|
||
const deserializedObject = parse(text); | ||
|
||
if (deserializedObject.root) { | ||
this.tagToLowerCase(deserializedObject.root); | ||
await Deno.writeTextFile(file.path, serialize(deserializedObject.root)); | ||
} | ||
|
||
} | ||
|
||
}; | ||
|
||
initialize = async () => { | ||
await this.markFiles(); | ||
await this.transform(); | ||
} | ||
|
||
/** | ||
* | ||
*/ | ||
constructor() { | ||
this.initialize(); | ||
} | ||
|
||
|
||
} | ||
|
||
export default new App(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * as std_fs from 'https://deno.land/std@0.74.0/fs/mod.ts'; | ||
export * as std_path from "https://deno.land/std@0.74.0/path/mod.ts"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# xml-tag-to-lowercase @ AOE3NativeED | ||
Transform all the xml tags to lower case, but leave all the values of attributes and xml contents untouched. | ||
|
||
e.g. | ||
|
||
Before: | ||
|
||
``` xml | ||
<ProtoAction> | ||
<Name>MeleeHandAttack</Name> | ||
<Damage>20.000000</Damage> | ||
<DamageType>Hand</DamageType> | ||
<ROF>1.00000</ROF> | ||
<DamageBonus type="AbstractCavalry">2.000000</DamageBonus> | ||
</ProtoAction> | ||
``` | ||
|
||
After: (after beautification) | ||
``` xml | ||
<protoaction> | ||
<name>MeleeHandAttack</name> | ||
<damage>20.000000</damage> | ||
<damagetype>Hand</damagetype> | ||
<rof>1.00000</rof> | ||
<damagebonus type="AbstractCavalry">2.000000</damagebonus> | ||
</protoaction> | ||
``` | ||
|
||
(Note: The result will be an one-line xml, so you may need a beautifier to do the further formatings.) | ||
|
||
## Prerequisite | ||
|
||
[deno](https://github.com/denoland/deno) > 1.0.0 | ||
|
||
## How to use this tool | ||
|
||
Step 1: Place all your xml files under `workshop` folder, and this tool will scan all the files in that folder, then filter out the xml files for you. | ||
|
||
(You don't need to worry about folder structure, as in the end the files will be overwritten in place.) | ||
|
||
Step 2: Run the following command: | ||
|
||
``` shell | ||
deno run --allow-read --allow-write --unstable app.ts | ||
``` | ||
|
||
Step 3: Check out the `workshop` folder, and you can see the transformation is complete. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
export interface Document { | ||
declaration: { | ||
attributes: {}; | ||
}; | ||
root: { | ||
name: string; | ||
attributes: {}; | ||
children: any[]; | ||
} | undefined; | ||
} | ||
|
||
export interface Xml { | ||
name: string; | ||
attributes: any; | ||
content?: string; | ||
children: Xml[]; | ||
} | ||
|
||
/** | ||
* Parse the given string of `xml`. | ||
* | ||
* @param {String} xml | ||
* @return {Object} | ||
* @api public | ||
*/ | ||
|
||
export function parse(xml: string): Document { | ||
xml = xml.trim(); | ||
|
||
// strip comments | ||
xml = xml.replace(/<!--[\s\S]*?-->/g, ""); | ||
|
||
return document(); | ||
|
||
/** | ||
* XML document. | ||
*/ | ||
|
||
function document(): Document { | ||
return { | ||
declaration: declaration(), | ||
root: tag() | ||
}; | ||
} | ||
|
||
/** | ||
* Declaration. | ||
*/ | ||
|
||
function declaration() { | ||
var m = match(/^<\?xml\s*/); | ||
if (!m) return; | ||
|
||
// tag | ||
var node: any = { | ||
attributes: {} | ||
}; | ||
|
||
// attributes | ||
while (!(eos() || is("?>"))) { | ||
var attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
} | ||
|
||
match(/\?>\s*/); | ||
|
||
return node; | ||
} | ||
|
||
/** | ||
* Tag. | ||
*/ | ||
|
||
function tag() { | ||
var m = match(/^<([\w-:.]+)\s*/); | ||
if (!m) return; | ||
|
||
// name | ||
var node: Xml = { | ||
name: m[1], | ||
attributes: {}, | ||
children: [] | ||
}; | ||
|
||
// attributes | ||
while (!(eos() || is(">") || is("?>") || is("/>"))) { | ||
var attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
} | ||
|
||
// self closing tag | ||
if (match(/^\s*\/>\s*/)) { | ||
return node; | ||
} | ||
|
||
match(/\??>\s*/); | ||
|
||
// content | ||
node.content = content(); | ||
|
||
// children | ||
var child; | ||
while ((child = tag())) { | ||
node.children.push(child); | ||
} | ||
|
||
// closing | ||
match(/^<\/[\w-:.]+>\s*/); | ||
|
||
return node; | ||
} | ||
|
||
/** | ||
* Text content. | ||
*/ | ||
|
||
function content() { | ||
var m = match(/^([^<]*)/); | ||
if (m) return m[1]; | ||
return ""; | ||
} | ||
|
||
/** | ||
* Attribute. | ||
*/ | ||
|
||
function attribute() { | ||
var m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); | ||
if (!m) return; | ||
return { name: m[1], value: strip(m[2]) }; | ||
} | ||
|
||
/** | ||
* Strip quotes from `val`. | ||
*/ | ||
|
||
function strip(val: string) { | ||
return val.replace(/^['"]|['"]$/g, ""); | ||
} | ||
|
||
/** | ||
* Match `re` and advance the string. | ||
*/ | ||
|
||
function match(re: RegExp) { | ||
var m = xml.match(re); | ||
if (!m) return; | ||
xml = xml.slice(m[0].length); | ||
return m; | ||
} | ||
|
||
/** | ||
* End-of-source. | ||
*/ | ||
|
||
function eos() { | ||
return 0 == xml.length; | ||
} | ||
|
||
/** | ||
* Check for `prefix`. | ||
*/ | ||
|
||
function is(prefix: string) { | ||
return 0 == xml.indexOf(prefix); | ||
} | ||
} | ||
|
||
export function serialize(...nodes: (Xml[])): string { | ||
|
||
const get_children = (tag: Xml) => | ||
(tag.content) | ||
? tag.content | ||
: tag.children | ||
.map((child) => serialize(child)) | ||
.join(""); | ||
|
||
const format_attributes = (node: Xml) => { | ||
|
||
let attributesString = ""; | ||
|
||
for (let key in node.attributes) { | ||
attributesString += ` ${key}="${node.attributes[key]}"`; | ||
} | ||
|
||
return attributesString; | ||
} | ||
|
||
|
||
const format_tag = (name: string, attributes: string, content?: string) => | ||
`<${name}${attributes.length > 0 | ||
? `${attributes}` | ||
: ``}>${content}</${name}>`; | ||
|
||
|
||
return (nodes as Array<Xml>) | ||
.map((node: Xml) => { | ||
|
||
const attributes = format_attributes(node); | ||
|
||
const tag = node as Xml; | ||
const children = get_children(tag); | ||
return format_tag(tag.name, attributes, children); | ||
|
||
}) | ||
.join(""); | ||
} |