Využij akce až 30 % zdarma při nákupu e-learningu. Více informací. Zároveň je tento týden sleva až 80 % na e-learning týkající se C# .NET
Hledáme nového kolegu do redakce - 100% home office, 100% flexibilní pracovní doba. Více informací.
discount week 30 halloween

Diskuze: Přepsání určitých textů/stringů v souboru

Aktivity
Avatar
Daniel Semerák:29. května 17:07

Zdravím.
Mám dva soubory v XML formátu a potřeboval bych přepsat určité řádky/stringy v cílovém souboru těmi v zdrojovém ale za podmínky, že se budou shodovat čísla stringů, ale se zachováním odřádkovaného textu.
Navíc bych potřeboval nějak ošetřit, aby v cílovém souboru zůstaly zachované stringy, které v zdrojovém souboru nejsou.
Nejlepší by byla konzole, když stačí zadat jen zdrojový a cílový soubor a ten cílový přepsat nebo vytvořit nový třetí soubor, kde už budou patřičné úpravy.
Problém je, že ačkoli jsem už něco málo dělal v C#, tak jen v GUI prostředí ale už ne konzolovou aplikaci a navíc nemám naprosto žádné zkušenosti s XML a vůbec netuším, jak přepsat data jen dle stringů a ne dle fyzických řádků a byly zachované nové stringy v cílovém souboru na jejich původním místě.
Snad jsem to vysvětlil a dole ukázal srozumitelně.
Díky moc za vaše rady a tipy a případnou pomoc s kodem, jelikož já jsem totálně mimo.

Zkusil jsem: Zatím nic, nebot to jsou pro mě naprosto neznámé vody. :-(

Chci docílit: Zdrojový soubor:
<string id ="1"> bojovník </string>
<string id ="2"> mág </string>
<string id ="3"> zloděj </string>
<string id ="4"> paladin </string>
<string id ="5"> klerik </string>
<string id ="6"> druid </string>
<string id ="7"> vědec </string>

<string id ="12"> Deník </string>

Cílový soubor:
<string id ="1"> warrior </string>
<string id ="2"> soccer </string>
<string id ="3"> thief </string>
<string id ="4"> paladin </string>
<string id ="5"> cleric </string>
<string id ="6"> druid </string>
<string id ="7"> science

Human-science.</string>
<string id ="12"> Journal </string>

Výsledek:
<string id ="1"> bojovník </string>
<string id ="2"> mág </string>
<string id ="3"> zloděj </string>
<string id ="4"> paladin </string>
<string id ="5"> klerik </string>
<string id ="6"> druid </string>
<string id ="7"> science

human-science.</string>
<string id ="12"> Deník </string>

 
Odpovědět
29. května 17:07
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Daniel Semerák
DarkCoder:30. května 2:59

Z tvého popisu usuzuji, že se snažíš počeštit cizí aplikaci.

Ano, smyslem celého snažení je vygenerování nového XML souboru, který později přejmenuješ na název cílového souboru. Jediné co potřebuješ znát je jak vypadá struktura XML souboru, že texty které budeš nahrazovat jsou uzavřeny mezi identifikovanými bloky.

Realizace je jednoduchá. V cílovém souboru postupně procházíš jednotlivé bloky a podle identifikátoru je dohledáváš ve zdrojovém souboru. Před vyhledáním provedeš analýzu na akceptované formátování. Pokud bude vše ok, najdeš blok ve zdrojovém souboru a zapíšeš ho do nového souboru. Pokud formátování nebude dle tvých představ, celý blok z cílového souboru zapíšeš do nového souboru. Vše co nenajdeš ve zdrojovém souboru tak z cílového souboru do nového opíšeš.

Dost úsilí ale vydáváš na vytvoření XML zdrojového souboru. Dobré by bylo si z cílového souboru vytáhnout texty mezi bloky, k těm přidat překlad a tyto přeložené texty implementovat do nového souboru postupem, který jsem výše uvedl. Vyhneš se tak zbytečnému vytváření XML struktury, kterou za tebe může vygenerovat program.

Nahoru Odpovědět
30. května 2:59
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Daniel Semerák:30. května 6:11

DarkCoder>
Prostě mám dva XML soubory, jeden počeštěný a druhý v angličtině, jenže v tom počeštěném jsou nějaké stringy, jež nemá ten anglický a v tom anglickém jsou zase stringy, jež nejsou v tom českém, tak chci právě ty nepočeštěné zachovat a zbylé stringy, jež se budou shodovat dle daných ID stringů.
Také chci zachovat formát odřádkování; tj. aby mi všechny stringy nehodil do jednoho řádku, ale bylo zachované i to klasické odřádkování.

Problém ale je, že vůbec netuším, jak takový kod mám napsat, takže bych byl moc rád, kdyby mi někdo s tím pomohl, tj. de facto ho napsal za mě. :-(
Teprve se C# učím a nevím, jestli tady bych a hlavně nevím, jak bych měl použít serializaci a deserializaci. :-(
... a to jsem si o tom pár návodů a stránek přečetl, ale stejně jsem z toho totálně tumpachový. :-(

 
Nahoru Odpovědět
30. května 6:11
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Daniel Semerák
DarkCoder:30. května 13:21

K realizaci potřebuješ znát akorát práci se souborem (otevření, zavření, čtení, zápis) a práci s řetězci.

V cílovém souboru hledáš bloky, uchováváš si jejich pozici a obsah. Vše co je vně opisuješ do nového souboru. Když budeš číst cílový soubor znak po znaku, tak zjistíš, že znaky nových řádků jsou mimo bloky a ty tak přímo zapisuješ do nového souboru a zachováš tak formátování. Nemůže se tedy stát, že jednotlivé bloky budou v novém souboru za sebou.

Když začneš číst cílový soubor, zjistíš že první znak je otevřená hranatá závorka, což značí, že si narazil na hlavičku bloku. Najdeš koncovou hranatou závorku. Obsah uvnitř si uložíš, můžeš klidně se závorkami. Zjistíš validitu, koncový blok je na konci stejného řádku, je tedy ok. Vygeneruješ si konec bloku (přidáním zpětného lomítka k hlavičce a oříznutím zbytku) a uchováš si pozici koncové hranaté závorky. Nyní prohledáváš zdrojový soubor a hledáš hlavičku kterou jsi si uložil. Pokud ji najdeš tak najdeš konec bloku a vše uvnitř včetně bloku zapíšeš do nového souboru. Pokud nenajdeš, tak opíšeš uložený blok z cílového souboru do nového.

Máš tedy uloženo:

<string id ="1">
a pozici koncové hranaté závorky ukončovacího bloku

Vygeneruješ koncový blok

</string>

Ve zdrojovém souboru najdeš

<string id ="1"> bojovník </string>

a toto celé zapíšeš do nového souboru.

Nyní pokračuješ v čtení cílového souboru. Narážíš na znak nového řádku. Jelikož je vně bloků, tak ho zapíšeš do nového souboru.
Takto pokračuješ dál a dál. Při čtení

<string id ="7">

Zjistíš, že obsah není validní, jeho bloky nejsou na stejném řádku. Tak ho z cílového souboru opíšeš do nového souboru se všemi formátovacími znaky.

Do nového souboru pak zapíšeš zbylý řádek ze zdrojového souboru čímž dostaneš výslednou podobu nového XML souboru.

<string id ="1"> bojovník </string>
<string id ="2"> mág </string>
<string id ="3"> zloděj </string>
<string id ="4"> paladin </string>
<string id ="5"> klerik </string>
<string id ="6"> druid </string>
<string id ="7"> science

human-science.</string>
<string id ="12"> Deník </string>

Nakonec jeho jméno pojmenuješ jménem cílového souboru. To je celé..

Nahoru Odpovědět
30. května 13:21
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Daniel Semerák:30. května 15:34

Jak to vysvětluješ, tak to vypadá snadně a jednoduše. :-)
Jenže, ačkoli sice umím pracovat s načtením a s uložením souborů, tak stejně to ostatní je pro mě už Vyšší Dívčí. :-(
Sice už jsem programoval jeden malý prográmek, sic ve WinFormu, ale ten se vůbec netýkal XML ani vše kolem toho.
Na tohle bych vážně potřeboval mít už hotový zdrojový kod od někoho jiného a z něj pak se učil chápat práci s XML.
Já vím, že je hodně stránek s kody pro XML a s jejich popisem, ale nenašel jsem žádný, který by řešil zrovna tuhle situaci.
Jsem jen začínající programátor v C#, který se to učí jen jako samouk z CodeSource, přes strýčka Gúgla a dalších lidí a také stylem pokus-omyl.
Přesto jsou oblasti, jež vůbec nejsem s to pochopit a hlavně vytvořit správný kod, ani jak začít.

 
Nahoru Odpovědět
30. května 15:34
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Daniel Semerák
DarkCoder:30. května 17:32

Pokud umíš pracovat se soubory a řetězci, pak si schopen to vyřešit. Nic víc nepotřebuješ. Zapomeň na pojem XML, tím že si se s ním nesetkal pak v tobě vytváří blok, že nevíš co dělat. Nahlížej na to jako na prostou posloupnost znaků uvozenou bloky s identifikátory.

Začni tím že vynajdeš hlavičku uvozeného textu (včetně ostrých závorek) a uložíš si ji do paměti.

Že si samouk není nic omezujícího. Mě také nikdo neučil, v C# jsem nenapsal jedinou řádku, ale přesto do detailu od pohledu vím jak to řešit. Vše je o zkušenostech, které také s rostoucím počtem napsaných řádků kódu získáš. Hlavní je se toho nebát..

Nahoru Odpovědět
30. května 17:32
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Daniel Semerák:30. května 19:07

No, umím jen načíst klas. TeXTový soubor, s ním pracovat a pak ho zase uložit, ale už nevím, jak pracovat se strukturovaným souborem. :-(
Ani nevím, jak mám zjistit validitu a vše, co popisuješ.
Prostě nevím, jak a čím začít a hlavně vůbec netuším, jak takový kod má vypadat a jak ho vytvořit.
Já jsem spíše servisní technik IT než programátor.
Děkuji ti za všechny rady, ale bez nějakého už hotového kodu jsem nahraný a totálně mimo.
Rád bych se naučil aspon C#, ale z toho, co ted už vím, tak jsem schopen - aspon z části - to pochopit už z hotového kodu a ten pak dál upravovat a doplnovat dle potřeby; ale bez základu nemám dál co a jak stavět.

 
Nahoru Odpovědět
30. května 19:07
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Daniel Semerák
Petr Štechmüller:30. května 19:31

Ahoj,

čtení strukturovaného souboru znak po znaku, když má jazyk již implementované parsery je dost nešťastné řešení.
V C# jsem dělal kdysi dávno, teď dělám v Javě, ale to je "to samé". Z článků tady na síti by jsi se dozvěděl, že existují alespoň dva způsoby pro čtení XML::

  1. SAX - https://www.itnetwork.cz/…-zapis-saxem, https://www.itnetwork.cz/…ni-xml-saxem
  2. DOM - https://www.itnetwork.cz/…rial-xml-dom

Ve svém příkladu uvedu použití DOM parseru. Sice to bude v Javě, ale pro C# to bude hodně obdobné. A jak říkáš, pokud teprve začínáš, tak si k tomu sedni a zkoušej. Tím se toho nejvíc naučíš. Když něco nebudeš vědět, zeptej se tu. Vždy se tu najde alespoň jeden člověk, který už podobný problém řešil, či tě alespoň dokáže návést na správné řešení.

Tento kus kódu mi v Javě vytvoří nový DOM parser a vrátí kořenový element v XML dokumentu.

public Element load(Path path) throws IOException, ParserConfigurationException, SAXException {
    LOGGER.info("Načítám XML soubor na cestě: {}.", path.toString());
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(path.toFile());

    return doc.getDocumentElement();
}

Na to mám navazující parsující metodu, která mi načte celé XML do paměti do mnou definované struktury:

public XmlNode parse(Element xmlRootElement) {
    int depth = 0;
    XmlNode rootNode = new XmlNode(xmlRootElement.getNodeName(), depth);

    readAttributes(rootNode, xmlRootElement);
    recursiveRead(rootNode, xmlRootElement, depth + 1);

    return rootNode;
}

protected void readAttributes(XmlNode rootNode, Node xmlRootElement) {
    NamedNodeMap attributes = xmlRootElement.getAttributes();
    if (attributes == null) {
        return;
    }
    for (int i = 0; i < attributes.getLength(); i++) {
        Attr item = (Attr) attributes.item(i);
        rootNode.attributes.add(new XmlNodeAttribute(rootNode, item.getName(), item.getValue()));
    }
}

protected boolean recursiveRead(XmlNode rootNode, Node xmlRootElement, int depth) {
    NodeList childNodes = xmlRootElement.getChildNodes();
    boolean hasElementNodes = false;
    List<String> comments = new ArrayList<>();
    for (int i = 0; i < childNodes.getLength(); i++) {
        Node item = childNodes.item(i);
        switch (item.getNodeType()) {
            case Node.ELEMENT_NODE:
                hasElementNodes = true;
                Element element = (Element) item;
                XmlNode leaf = new XmlNode(element.getNodeName(), depth, rootNode);
                leaf.comments.addAll(comments);
                comments.clear();
                readAttributes(leaf, element);
                if (!recursiveRead(leaf, element, depth + 1)) {
                    leaf.content = element.getTextContent();
                }
                rootNode.children.add(leaf);
                break;
            case Node.COMMENT_NODE:
                comments.add(item.getNodeValue());
                break;
            case Node.TEXT_NODE:
                if ("#text".equals(item.getNodeName())) {
                    continue;
                }
                break;
        }
    }
    return hasElementNodes;
}

Ta struktura je definována velmi jednoduše za pomoci třídy XmlNode:

public class XmlNode {

    public final XmlNode parent;
    public final int depth;
    public final List<XmlNodeAttribute> attributes = new ArrayList<>();
    public final List<String> comments = new ArrayList<>();
    public final List<XmlNode> children = new LinkedList<>();
    public String name;
    public String content;

    private final String depthSpace;

    public XmlNode(String name, int depth) {
        this(name, depth, null);
    }

    public XmlNode(String name, XmlNode parent) {
        this(name, parent.depth + 1, parent);
    }

    public XmlNode(String name, int depth, XmlNode parent) {
        this.name = name;
        this.depth = depth;
        this.parent = parent;
        this.content = "";
        depthSpace = " ".repeat(depth);
    }

Tím si načteš oba dva překlady - český a anglický. Pak budeš procházet oba grafy do hloubky. No a na základě nějaké tvé logiky budeš sestavovat nový třetí (výsledný) graf. Ten se opět bude skládat z XmlNodů. Nakonec vše zase zpět převedeš na XML:

@Override
    public Document serialize(XmlNode rootNode) throws ParserConfigurationException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.newDocument();

        Element rootElement = document.createElement(rootNode.name);
        document.appendChild(rootElement);
        writeComments(document, rootElement, rootNode.comments);
        writeAttributes(rootElement, rootNode.attributes);

        serialize(document, rootElement, rootNode.children);

        return document;
    }

    private void serialize(Document document, Element rootElement, List<XmlNode> children) {
        for (XmlNode child : children) {
            Element childElement = document.createElement(child.name);
            rootElement.appendChild(childElement);

            writeComments(document, childElement, child.comments);
            writeAttributes(childElement, child.attributes);
            if (child.children.isEmpty()) {
                childElement.setTextContent(child.content);
            } else {
                serialize(document, childElement, child.children);
            }

        }
    }

    private void writeComments(Document document, Element element, List<String> comments) {
        for (String comment : comments) {
            Comment c = document.createComment(comment);
            element.getParentNode().insertBefore(c, element);
        }
    }

    private void writeAttributes(Element element, List<XmlNodeAttribute> attributes) {
        for (XmlNodeAttribute attribute : attributes) {
            element.setAttribute(attribute.key, attribute.value);
        }
    }

Na konec bych chtěl říct. Je to úplně opačný směr, než ti nabízí kolega. Je jen na tobě, jestli ten kód vezmeš a v rámci svého snažení ho přetransformuješ do C# tak, aby ti to fungovalo dle očekávání.
Pokud budeš mít ke kódu jakékoliv připomínky, určitě se ptej, rád je zodpovím.
Kód dávám k dispozici s tím, že je mi jedno, jak s ním kdokoliv naloží, ale neručím za následky použití tohoto kódu.

Hodně štěstí.

Nahoru Odpovědět
30. května 19:31
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Daniel Semerák
DarkCoder:30. května 21:32

XML soubor je určitá forma textového souboru. Jediné v čem se to nepatrně liší je způsob vyhledávání a vytahování dat. Nicméně použité nástroje jsou stále stejné.

Podoba nového souboru bude podobná cílovému souboru, pouze s odlišnými daty. Proto můžeš postupovat sekvenčně skrz cílový soubor, hledat identifikátor, dohledat jej ve zdrojovém souboru a aktualizovat nový soubor. Jelikož podoba cílového a zdrojového souboru souboru je obdobná, je záměna dát přímočará a rychlá. Nemusíš procházet celý soubor znova.

Abys viděl jak to funguje a viděl úzkou souvislost, zpracuj si následující příklad:

Máš řetězec

abc12defg345hi678jkl­mnop9012rstuv3wxyz

Nahraď všechna lichá čísla písmenem 'X' a všechna sudá čísla písmenem 'Y'.

Smyslem tohoto příkladu je poznat jaké úkony jsou třeba pro vyřešení příkladů a vidět souvislosti s tím co chceš udělat.

Jinak nic Ti nebrání v tom naučit se alespoň základy programování, třeba v jazyce C#. Poznáš tak jak vypadá takový program, čím začínat apod. Jak s tím budeš experimentovat, budeš vnímat souvislosti a budeš později schopen psát komplikovanější programy, které Ti mohou v lecčem dosti usnadnit práci. C# je hodně rozšířený, pro začínající určitě vhodný. Díky tomu v tom nezůstaneš sám a jak už tu bylo zmíněno, vždy se tu najde někdo kdo Ti poradí a celé to tak bude jednodušší.

Nahoru Odpovědět
30. května 21:32
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Daniel Semerák:23. srpna 19:17

Nakonec jsem našel na webu program, který to už umí, takže už jsem neměl důvod vytvářet nový.
Přesto všem, kteří reagovali na můj dotaz a chtěli mi pomoci, moc děkuji. :-)

Akceptované řešení
+5 Zkušeností
Řešení problému
 
Nahoru Odpovědět
23. srpna 19:17
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.