AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 717339
Accepted
cas
cas
Asked: 2022-09-15 16:55:37 +0800 CST2022-09-15 16:55:37 +0800 CST 2022-09-15 16:55:37 +0800 CST

como excluir um div com uma classe específica do XHTML usando o xstarlet?

  • 772

Eu tenho várias centenas de arquivos .xhtml em um subdiretório(*) e quero excluir todos os DIVs com uma classe específica (e todo o conteúdo desses DIVs - incluindo outros divs, spans, elementos de imagem e parágrafo) deles. O DIV pode aparecer zero, uma ou mais vezes em qualquer profundidade arbitrária dentro de cada arquivo .xhtml.

Os DIVs específicos que quero excluir são:

<div class="portlet solid author-note-portlet">.....</div>

Usando o xml_greputilitário do módulo perl XML::Twig , posso executar xml_grep -v 'div[@class="portlet solid author-note-portlet"]' file*.xhtmle ele removerá todas as instâncias dessa div dos arquivos .xhtml e exibirá o resultado em stdout. Exatamente o que eu quero, exceto por "exibir no stdout".

Se xml_greptivesse algum tipo de opção de edição no local, tudo bem, eu apenas usaria isso .... mas não, então eu teria que escrever um script wrapper que usasse um arquivo temporário ou spongee executar xml_grep em cada arquivo .xhtml individualmente, o que seria lento e tedioso. Ou eu poderia hackear uma cópia do xml_grep para que ele pudesse editar seu(s) arquivo(s) de entrada.

Mas não quero fazer nenhuma dessas coisas, quero usar a ferramenta existente que já pode fazer isso, quero usar xmlstarlet- será mais rápido, tem edição no local e não precisarei execute-o uma vez por nome de arquivo.

O problema é que não importa o que eu tente (e já tentei dezenas de variações), não consigo descobrir a especificação xpath correta para excluir um div com essa classe. por exemplo, eu tentei:

xmlstarlet ed -d "div[@class='portlet solid author-note-portlet']" file.xhtml

e (com cotação diferente)

xmlstarlet ed -d 'div[@class="portlet solid author-note-portlet"]' file.xhtml

e

xmlstarlet ed -d '//html/body/div/div/div[@class="portlet solid author-note-portlet"]'

e dezenas de outras variações. Nenhum deles resultou em qualquer alteração na saída xhtml. Este é o ponto em que eu costumo desistir de xmlstarlet e escrever um script perl, mas desta vez estou determinado a fazê-lo com xmlstarlet.

Então, qual é a maneira correta de especificar essa classe div para xmlstarlet?

BTW, para um exemplo de arquivo .xhtml (com duas instâncias deste div, que estão na mesma profundidade ... o que é bastante típico, mas não universal), xmlstarlet el -vdiz:

$ xmlstarlet el -v OEBPS/file0007.xhtml | grep author-note-portlet
html/body/div/div[@class='portlet solid author-note-portlet']
html/body/div/div[@class='portlet solid author-note-portlet']

(*) Não que isso importe, mas esses arquivos .xhtml estão dentro de um arquivo .epub(**) gerado pelo plugin FanFicFare para Caliber - que baixa todos os capítulos de livros em vários sites de ficção e os transforma em um arquivo epub ( que é basicamente um arquivo zip contendo arquivos XHTML e CSS e talvez arquivos jpeg ou gif, junto com um monte de arquivos de metadados).

<div class="portlet solid author-note-portlet">é usado por um site (Royal Road) para que os autores incluam uma nota com um capítulo. Alguns autores o usam com moderação e inserem notas curtas sobre o capítulo ou o livro ou anúncios breves sobre coisas aleatórias, talvez com um link para sua página do patreon... tudo bem, não é grande coisa.

Outros o usam para adicionar uma nota de meia página com links para 10 de seus outros livros no início de cada capítulo e novamente para adicionar três páginas e meia de links (com imagens de capa) a esses livros no final de cada capítulo. O que é meio bom se você estiver lendo em forma de série capítulo por capítulo no site, mas não se estiver lendo como um livro - ~ 4 páginas de autopromoção para cada 6-10 ou então as páginas da história são excessivas e distrativas. E, BTW, são 4 "páginas" no meu tablet Android de 10 polegadas - é mais que o dobro no meu telefone.

Eu posso facilmente adicionar display: noneà folha de estilo do epub para esta classe, mas eu quero realmente excluir os divs dos arquivos .xhtml. Eles aumentam notavelmente o tamanho do arquivo .epub.

(**) extrair o conteúdo do .epub com descompactação e reconstruí-lo posteriormente está fora do escopo desta questão, portanto, não se distraia com detalhes irrelevantes. Já tratado.


Exemplo de arquivo .xhtml, editado ao mínimo (e história/capítulo/nome do autor anonimizado para proteger o "culpado :-):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Chapter Five - Chapter Name</title>
<link href="stylesheet.css" type="text/css" rel="stylesheet"/>
<meta name="chapterurl" content="https://www.royalroad.com/fiction/URL"/>
<meta name="chapterorigtitle" content="Chapter Five - Chapter Name"/>
<meta name="chaptertoctitle" content="Chapter Five - Chapter Name"/>
<meta name="chaptertitle" content="Chapter Five - Chapter Name"/>
</head>
<body class="fff_chapter">
<h3 class="fff_chapter_title">Chapter Five - Chapter Name</h3>
<div class="chapter-inner chapter-content"><div class="portlet solid author-note-portlet">
                    <div class="portlet-title">
                        <div class="caption">
                            <i class="fa fa-sticky-note"></i>
                            <span class="caption-subject bold uppercase">A note from Author Name</span>
                        </div>
                    </div>
                    <div class="portlet-body author-note"><p><span>About a dozen or so p, span, img, and br tags here</span></p>
</div>
                </div>
<p> story text here.  a few hundreds p, br, etc tags
</p>
            <div class="portlet solid author-note-portlet">
                    <div class="portlet-title">
                        <div class="caption">
                            <i class="fa fa-sticky-note"></i>
                            <span class="caption-subject bold uppercase">A note from Author Name</span>
                        </div>
                    </div>
                    <div class="portlet-body author-note"><p>several dozen more p, span, br, img, etc tags here</p>
</div>
                </div>
</div>
</body>
</html>
xmlstarlet
  • 2 2 respostas
  • 244 Views

2 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2022-09-15T22:26:11+08:002022-09-15T22:26:11+08:00

    A maneira correta de fazer isso xmlstarleté

    xmlstarlet ed --inplace -N xmlns="http://www.w3.org/1999/xhtml" \
        --delete '//xmlns:div[@class="portlet solid author-note-portlet"]' file
    

    ou, usando opções curtas,

    xmlstarlet ed -L -N xmlns="http://www.w3.org/1999/xhtml" \
        -d '//xmlns:div[@class="portlet solid author-note-portlet"]' file
    

    Como o documento usa um namespace padrão, precisamos informar xmlstarletque todos os nós pertencem a esse namespace e também prefixar o nome do nó com o espaço reservado para namespace na expressão XPath.

    De acordo com a documentação, -Ndeve ser a última "opção global", ou seja, deve vir depois -L(outra opção global). A -dé a "operação de exclusão" para xmlstarlet ed, portanto, não é uma das opções globais.

    O XPath //xmlns:divprocurará recursivamente por um nó chamado divno xmlnsnamespace.

    Na pergunta, além de não manipular o namespace, você especificou isso de forma insuficiente ou excessiva. Usar div, que é o mesmo que /div, corresponderia a um nó raiz e //html/body/div/div/divcorresponderia a um nó filho imediato de html/body/div/div, em qualquer lugar.


    O yqwrapper (por Andrey Kislyuk) em torno do processador JSON jqvem com um wrapper do analisador XML chamadoxq . Você pode usar isso também:

    xq -x 'del(.. | .div? | select(."@class"? == "portlet solid author-note-portlet"))' file
    

    A opção -x( --xml-output) fornece saída XML em vez de saída JSON. Usar xqcom -i( --in-place) fará com que ele faça a edição no local.

    Este analisador XML não se importa com namespaces.

    • 8
  2. eff
    2022-09-16T05:39:32+08:002022-09-16T05:39:32+08:00

    Uma nota separada seria, dado que você pode obter a filtragem desejada com xml_grep, você teria resolvido o problema em muito menos tempo do que levaria para escrever sua pergunta para usar algo como os seguintes comandos bash

        mkdir temp
        for file in <subdir>/*.xhtml; do
            # Your magic xml_grep command
            xml_grep -v 'div[@class="portlet solid author-note-portlet"]' "$file" > "temp/$file"
        done
        rm -r subdir
        mv temp subdir
    

    Por outro lado, há mérito e satisfação em aprender a usar outras ferramentas.

    • -1

relate perguntas

  • insira uma linha em xml usando xmlstarlet

  • XmlStarlet xml para saída csv como 'NaNNaNNaN'

  • Editar XML usando xmlstarlet apenas em um subnó

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve