Ejemplo n.º 1
0
    def _processTable(self, table):
        self._currentSection.openTag("table", frame="box", rules="all")

        for child in table:
            if child.tag.endswith("tr"):
                self._currentSection.openTag("tr")

                for node in child:
                    if node.tag.endswith("tc"):
                        if utils.hasText(node):
                            paragraphsCount = utils.xpath(node, "count(w:p)")

                            # Uso el tag "p" si hay más de un párrafo.
                            if paragraphsCount > 1:
                                self._currentSection.openTag("td")
                                self._processMainContent(node, "p")
                                self._currentSection.closeTag("td")
                            else:
                                self._processMainContent(node, "td")
                        else:
                            # No puedo ignorar la celda si no tiene texto!
                            self._currentSection.openTag("td")
                            self._currentSection.closeTag("td")

                self._currentSection.closeTag("tr")

        self._currentSection.closeTag("table")
Ejemplo n.º 2
0
    def _processTable(self, table):
        self._currentSection.openTag("table", frame="box", rules="all")

        for child in table:
            if child.tag.endswith("tr"):
                self._currentSection.openTag("tr")

                for node in child:
                    if node.tag.endswith("tc"):
                        if utils.hasText(node):
                            paragraphsCount = utils.xpath(node, "count(w:p)")

                            # Uso el tag "p" si hay más de un párrafo.
                            if paragraphsCount > 1:
                                self._currentSection.openTag("td")
                                self._processMainContent(node, "p")
                                self._currentSection.closeTag("td")
                            else:
                                self._processMainContent(node, "td")
                        else:
                            # No puedo ignorar la celda si no tiene texto!
                            self._currentSection.openTag("td")
                            self._currentSection.closeTag("td")

                self._currentSection.closeTag("tr")

        self._currentSection.closeTag("table")
Ejemplo n.º 3
0
    def getRawText(self):
        docText = "".join(
            utils.xpath(self._documentXml,
                        "//w:t[not(ancestor::mc:Fallback)]/text()"))
        footnotesText = "".join(
            self._footnotes.getRawText()) if self._footnotes else ""

        return docText + footnotesText
Ejemplo n.º 4
0
    def _readDocumentFullPath(self):
        rels = etree.parse(self._docx.open("_rels/.rels"))
        documentName = utils.xpath(
            rels.getroot(),
            "/rels:Relationships/rels:Relationship[@Type = '{0}']/@Target".
            format(Docx._DOCUMENT))

        if not documentName:
            raise converter_base.InvalidFile("No existe document.xml.")

        return documentName[0]
Ejemplo n.º 5
0
    def _processAlternateContent(self, alternateContent):
        paragraphs = utils.xpath(alternateContent, "mc:Choice//w:p")

        # En mc:AlternateContent los párrafos generalmente se encuentran dentro de w:txtbxContent.
        # Sin embargo, ese nodo puede contener otro nodo w:sdt, que a su vez puede contener párrafos...
        # Lo que significa que necesito todos estos párrafos bajo un mismo padre, para poder procesarlos con
        # el método _processMainContent, por eso es que los agrego directamente como hijos de AlternateContent.
        for p in paragraphs:
            alternateContent.append(p)
            pass

        self._processMainContent(alternateContent, "span")
Ejemplo n.º 6
0
    def _processAlternateContent(self, alternateContent):
        paragraphs = utils.xpath(alternateContent, "mc:Choice//w:p")

        # En mc:AlternateContent los párrafos generalmente se encuentran dentro de w:txtbxContent.
        # Sin embargo, ese nodo puede contener otro nodo w:sdt, que a su vez puede contener párrafos...
        # Lo que significa que necesito todos estos párrafos bajo un mismo padre, para poder procesarlos con
        # el método _processMainContent, por eso es que los agrego directamente como hijos de AlternateContent.
        for p in paragraphs:
            alternateContent.append(p)
            pass

        self._processMainContent(alternateContent, "span")
Ejemplo n.º 7
0
    def _readStyles(self, stylesXml):
        xml = etree.parse(stylesXml)
        styles = {}

        for child in xml.getroot():
            if child.tag.endswith("}style"):
                attr = utils.getAttr(child, "w:type")
                if attr == "paragraph" or attr == "character":
                    styleId = utils.getAttr(child, "w:styleId")
                    styleName = utils.xpath(child, "w:name/@w:val")[0]

                    formatNode = utils.find(child, "w:rPr" if attr == "character" else "w:pPr")

                    # En los estilos, ignoro si tienen aplicado el formato subíndice o superíndice. Una de las
                    # razones es que abby finereader no parece utilizar este mecanismo al utilizar subs o sups, sino
                    # que utiliza directamente las etiquetas de formato en el run. Pero el motivo principal es que
                    # el word le aplica a las referencias a las notas un estilo con el formato superíndice y en este
                    # caso particular no debería procesarlos. Podría de alguna manera comprobar si el estilo es el
                    # que word usa para las referencias a las notas, y en ese caso ignorar el formato, pero esto
                    # solo me complicaría las cosas.
                    formats = utils.getFormats(formatNode, False) if formatNode is not None else []
                    styles[styleId] = (styleName, self._styleNameToClassName(styleName), formats)

        return styles
Ejemplo n.º 8
0
    def getRawText(self):
        docText = "".join(utils.xpath(self._documentXml, "//w:t[not(ancestor::mc:Fallback)]/text()"))
        footnotesText = "".join(self._footnotes.getRawText()) if self._footnotes else ""

        return docText + footnotesText
Ejemplo n.º 9
0
    def _processRun(self, run, previousRunFormats):
        styleId = self._styles.getRunStyleId(run)

        rpr = utils.find(run, "w:rPr")
        runFormats = utils.getFormats(rpr) if rpr is not None else []

        isLastRun = utils.getNextRun(run) is None
        needToCloseSpan = False
        needToOpenSpan = False
        className = ""

        # Si el run tiene aplicado un estilo, este estilo puede tener asociado formatos, por
        # ejemplo: negrita, cursiva, etc. Proceso también estos formatos.
        if styleId:
            disabledRunFormats = utils.getDisabledFormats(rpr) if rpr is not None else []
            formats = runFormats + disabledRunFormats
            for f in (f for f in self._styles.getStyleFormats(styleId) if f not in formats):
                runFormats.append(f)

            className = self._styles.getRunClassName(run)

            if className:
                previousRunStyleId = None
                nextRunStyleId = None

                previousRun = utils.getPreviousRun(run)
                nextRun = utils.getNextRun(run)

                if previousRun is not None:
                    previousRunStyleId = self._styles.getRunStyleId(previousRun)

                if nextRun is not None:
                    nextRunStyleId = self._styles.getRunStyleId(nextRun)

                if styleId != previousRunStyleId:
                    needToOpenSpan = True

                if styleId != nextRunStyleId:
                    needToCloseSpan = True

        # Cada vez que tengo que abrir un span porque es necesario incluir un estilo
        # propio, entonces cierro absolutamente todos los tags de formato que estén abiertos.
        # Supongamos que tengo este texto:
        #   <strong>aaaaa<span>aaaabbbb</span></strong>
        # Ahora, quiero cerrar el "strong" al comienzo de "bbbb". Para ello tengo dos
        # opciones:
        #   1- <strong>aaaaa<span>aaaa</span></strong><span>bbbb</span>
        #   2- <strong>aaaaa</strong><span><strong>aaaa</strong>bbbb</span>
        # En la primera, lo que cierro y abro son los spans; en la segunda, son
        # los strongs. Yo opté implementar la segunda opción.
        # Ahora bien, puede suceder lo siguiente. Supongamos este texto:
        #   aaaaaaaaaaa<span>bbbbbbb</span>cccccccccccc
        # Si ese texto tuviera aplicado negrita desde el comienzo hasta el final, lo
        # óptimo sería hacer:
        #   <strong>aaaaaaaaaaa<span>bbbbbbb</span>cccccccccccc</strong>
        # Sin embargo, dado que cierro todos los tags antes del comienzo de un span, resulta
        # esto:
        #   <strong>aaaaaaaaaaa</strong><span><strong>bbbbbbb</strong></span><strong>cccccccccccc</strong>
        # El problema es que de antemano no puedo saber hasta donde se extiende el strong, porque tal vez
        # tenga que cerrarlo en medio de un span, como en el ejemplo anterior, y entonces debo cerrar primero
        # el span, luego el strong, y luego abrir el span de vuelta, para no causar un error de anidamiento.
        # Creo que está bien dejarlo así (es decir, abrir y cerrar la menor cantidad de spans posiles), porque
        # de todas maneras es más fácil para el browser procesar varios strongs (o cualquier otro
        # tag de formato, como em) que varios spans con una clase.
        if runFormats != previousRunFormats or needToOpenSpan:
            for f in reversed(previousRunFormats):
                self._currentSection.closeTag(f)

            # Dado el caso de un run que contenga un estilo y formatos, entonces abro
            # el span primero, y dentro del span abro los formatos.
            if needToOpenSpan:
                self._currentSection.openTag("span", **{"class": className})

            for f in runFormats:
                self._currentSection.openTag(f)

        for child in run:
            if child.tag.endswith("}t"):
                self._currentSection.appendText(child.text)
            elif child.tag.endswith("}footnoteReference"):
                footnoteId = utils.xpath(run, "w:footnoteReference/@w:id")[0]
                self._footnotesId.append(footnoteId)
                self._currentSection.insertNoteReference()
            elif child.tag.endswith("}drawing") or child.tag.endswith("}pict"):
                imagesId = utils.getImagesId(child)
                if imagesId:
                    self._processImage(imagesId[0])
            elif child.tag.endswith("}br") and not child.attrib:
                self._currentSection.openTag("br")
                self._currentSection.closeTag("br")
            elif child.tag.endswith("}AlternateContent"):
                self._processAlternateContent(child)

        if needToCloseSpan:
            # No puedo simplemente cerrar el span, porque puede haber tags de formato abiertos
            # dentro del span: necesito cerrar esos tags primero.
            isSpanClosed = False
            while not isSpanClosed:
                try:
                    self._currentSection.closeTag("span")
                    isSpanClosed = True
                except ebook_data.CloseTagMismatchError as e:
                    self._currentSection.closeTag(e.expected)

            # Dado que cuando abro un span cierro todos los tags de formato, puedo asumir
            # que todos los tags de formato que cerré arriba eran todos los que estaban en
            # runFormats. Ahora bien, como al cerrar el span cerré todos los tags de formato, eso
            # significa que desde el punto de vista del run siguiente, no hay tags de formatos previos
            # abiertos, por eso debo retornar una lista vacía de formatos.
            runFormats = []
        elif isLastRun:
            for f in reversed(runFormats):
                self._currentSection.closeTag(f)

        return runFormats
Ejemplo n.º 10
0
    def _processRun(self, run, previousRunFormats):
        styleId = self._styles.getRunStyleId(run)

        rpr = utils.find(run, "w:rPr")
        runFormats = utils.getFormats(rpr) if rpr is not None else []

        isLastRun = utils.getNextRun(run) is None
        needToCloseSpan = False
        needToOpenSpan = False
        className = ""

        # Si el run tiene aplicado un estilo, este estilo puede tener asociado formatos, por
        # ejemplo: negrita, cursiva, etc. Proceso también estos formatos.
        if styleId:
            disabledRunFormats = utils.getDisabledFormats(
                rpr) if rpr is not None else []
            formats = runFormats + disabledRunFormats
            for f in (f for f in self._styles.getStyleFormats(styleId)
                      if f not in formats):
                runFormats.append(f)

            className = self._styles.getRunClassName(run)

            if className:
                previousRunStyleId = None
                nextRunStyleId = None

                previousRun = utils.getPreviousRun(run)
                nextRun = utils.getNextRun(run)

                if previousRun is not None:
                    previousRunStyleId = self._styles.getRunStyleId(
                        previousRun)

                if nextRun is not None:
                    nextRunStyleId = self._styles.getRunStyleId(nextRun)

                if styleId != previousRunStyleId:
                    needToOpenSpan = True

                if styleId != nextRunStyleId:
                    needToCloseSpan = True

        # Cada vez que tengo que abrir un span porque es necesario incluir un estilo
        # propio, entonces cierro absolutamente todos los tags de formato que estén abiertos.
        # Supongamos que tengo este texto:
        #   <strong>aaaaa<span>aaaabbbb</span></strong>
        # Ahora, quiero cerrar el "strong" al comienzo de "bbbb". Para ello tengo dos
        # opciones:
        #   1- <strong>aaaaa<span>aaaa</span></strong><span>bbbb</span>
        #   2- <strong>aaaaa</strong><span><strong>aaaa</strong>bbbb</span>
        # En la primera, lo que cierro y abro son los spans; en la segunda, son
        # los strongs. Yo opté implementar la segunda opción.
        # Ahora bien, puede suceder lo siguiente. Supongamos este texto:
        #   aaaaaaaaaaa<span>bbbbbbb</span>cccccccccccc
        # Si ese texto tuviera aplicado negrita desde el comienzo hasta el final, lo
        # óptimo sería hacer:
        #   <strong>aaaaaaaaaaa<span>bbbbbbb</span>cccccccccccc</strong>
        # Sin embargo, dado que cierro todos los tags antes del comienzo de un span, resulta
        # esto:
        #   <strong>aaaaaaaaaaa</strong><span><strong>bbbbbbb</strong></span><strong>cccccccccccc</strong>
        # El problema es que de antemano no puedo saber hasta donde se extiende el strong, porque tal vez
        # tenga que cerrarlo en medio de un span, como en el ejemplo anterior, y entonces debo cerrar primero
        # el span, luego el strong, y luego abrir el span de vuelta, para no causar un error de anidamiento.
        # Creo que está bien dejarlo así (es decir, abrir y cerrar la menor cantidad de spans posiles), porque
        # de todas maneras es más fácil para el browser procesar varios strongs (o cualquier otro
        # tag de formato, como em) que varios spans con una clase.
        if runFormats != previousRunFormats or needToOpenSpan:
            for f in reversed(previousRunFormats):
                self._currentSection.closeTag(f)

            # Dado el caso de un run que contenga un estilo y formatos, entonces abro
            # el span primero, y dentro del span abro los formatos.
            if needToOpenSpan:
                self._currentSection.openTag("span", **{"class": className})

            for f in runFormats:
                self._currentSection.openTag(f)

        for child in run:
            if child.tag.endswith("}t"):
                self._currentSection.appendText(child.text)
            elif child.tag.endswith("}footnoteReference"):
                footnoteId = utils.xpath(run, "w:footnoteReference/@w:id")[0]
                self._footnotesId.append(footnoteId)
                self._currentSection.insertNoteReference()
            elif child.tag.endswith("}drawing") or child.tag.endswith("}pict"):
                imagesId = utils.getImagesId(child)
                if imagesId:
                    self._processImage(imagesId[0])
            elif child.tag.endswith("}br") and not child.attrib:
                self._currentSection.openTag("br")
                self._currentSection.closeTag("br")
            elif child.tag.endswith("}AlternateContent"):
                self._processAlternateContent(child)

        if needToCloseSpan:
            # No puedo simplemente cerrar el span, porque puede haber tags de formato abiertos
            # dentro del span: necesito cerrar esos tags primero.
            isSpanClosed = False
            while not isSpanClosed:
                try:
                    self._currentSection.closeTag("span")
                    isSpanClosed = True
                except ebook_data.CloseTagMismatchError as e:
                    self._currentSection.closeTag(e.expected)

            # Dado que cuando abro un span cierro todos los tags de formato, puedo asumir
            # que todos los tags de formato que cerré arriba eran todos los que estaban en
            # runFormats. Ahora bien, como al cerrar el span cerré todos los tags de formato, eso
            # significa que desde el punto de vista del run siguiente, no hay tags de formatos previos
            # abiertos, por eso debo retornar una lista vacía de formatos.
            runFormats = []
        elif isLastRun:
            for f in reversed(runFormats):
                self._currentSection.closeTag(f)

        return runFormats
Ejemplo n.º 11
0
 def getFootnote(self, footnoteId):
     return utils.xpath(self._footnotesXml, 'w:footnote[@w:id = "{0}"]'.format(footnoteId))[0]
Ejemplo n.º 12
0
 def getRawText(self):
     return "".join(utils.xpath(self._footnotesXml, "//w:t/text()"))
Ejemplo n.º 13
0
 def getRunStyleId(self, run):
     styleId = utils.xpath(run, "w:rPr/w:rStyle/@w:val")
     return styleId[0] if styleId else None
Ejemplo n.º 14
0
 def getParagraphStyleId(self, paragraph):
     styleId = utils.xpath(paragraph, "w:pPr/w:pStyle/@w:val")
     return styleId[0] if styleId else None