2

lxmlを使用してXHTMLをレンダリングする場合、名前空間のプレフィックスが付いたXHTML要素とjavascriptを処理できないように見えるFirefoxを使用しない限り、すべて問題ありません。Operaはjavascript(これはjQueryとMathJaxの両方に適用されます)を正常に実行できますが、XHTML名前空間にプレフィックスがあるかどうかに関係なく(h:私の場合)、Firefoxではスクリプトは奇妙なエラーで中止さthis.headます( MathJaxの場合)。

関数については知っていますが、名前空間プレフィックスとしてregister_namespaceも受け入れNoneません。""モジュールで聞いたこと_namespace_mapがありlxml.etreeますが、Pythonがこの属性が存在しないと文句を言います(バージョンの問題?)

XHTML名前空間の名前空間プレフィックスを削除する他の方法はありますか?str.replace別の関連する質問への回答で示唆されているように、XMLセマンティクスを認識しておらず、結果のドキュメントを簡単に台無しにする可能性があるため、私が受け入れることができる方法ではないことに注意してください

リクエストに応じて、すぐに使用できる2つの例があります。1つは名前空間プレフィックスがあり、もう1つは。がありません。最初のものはFirefoxで0を表示し(間違っています)、2番目のものは1を表示します(正しい)。Operaは両方を正しくレンダリングします。これは明らかにFirefoxのバグですが、これはlxmlでプレフィックスなしのXHTMLが必要な理由としてのみ機能します。モバイルクライアントなどのトラフィックを減らす理由は他にもあります(h:数十または数百のhtmlタグを考慮するとかなり多くなります) 。

4

3 に答える 3

8

デフォルトの名前空間にマップするを使用ElementMakerして指定します。nsmapNone

#!/usr/bin/env python
# dogeml.py

from lxml.builder import ElementMaker
from lxml import etree

E = ElementMaker(
    nsmap={
        None: "http://wow/"    # <--- This is the special sauce
    }
)

doge = E.doge(
    E.such('markup'),
    E.many('very namespaced', syntax="tricks")
)

options = {
    'pretty_print': True,
    'xml_declaration': True,
    'encoding': 'UTF-8',
}

serialized_bytes = etree.tostring(doge, **options)
print(serialized_bytes.decode(options['encoding']))

このスクリプトの出力からわかるように、デフォルトの名前空間が定義されていますが、タグにはプレフィックスがありません。

<?xml version='1.0' encoding='UTF-8'?>
<doge xmlns="http://wow/">
   <such>markup</such>
   <many syntax="tricks">very namespaced</many>
</doge>

このコードをPython2.7.6、3.3.5、および3.4​​.0とlxml3.3.1と組み合わせてテストしました。

于 2014-04-07T01:50:42.193 に答える
2

このXSL変換contentは、ルートノードで定義された名前空間を維持しながら、からすべてのプレフィックスを削除します。

import lxml.etree as ET

content = '''\
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ml="http://foo">
  <h:head>
    <h:title>MathJax Test Page</h:title>
    <h:script type="text/javascript"><![CDATA[
      function test() {
        alert(document.getElementsByTagName("p").length);
      };
    ]]></h:script>
  </h:head>
  <h:body onload="test();">
    <h:p>test</h:p>
    <ml:foo></ml:foo>
  </h:body>
</h:html>
'''
dom = ET.fromstring(content)

xslt = '''\
<xsl:stylesheet version="1.0"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>

<!-- identity transform for everything else -->
<xsl:template match="/|comment()|processing-instruction()|*|@*">
    <xsl:copy>
      <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

<!-- remove NS from XHTML elements -->
<xsl:template match="*[namespace-uri() = 'http://www.w3.org/1999/xhtml']">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()" />
    </xsl:element>
</xsl:template>

<!-- remove NS from XHTML attributes -->
<xsl:template match="@*[namespace-uri() = 'http://www.w3.org/1999/xhtml']">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>
</xsl:stylesheet>
'''

xslt_doc = ET.fromstring(xslt)
transform = ET.XSLT(xslt_doc)
dom = transform(dom)

print(ET.tostring(dom, pretty_print = True, 
                  encoding = 'utf-8'))

収量

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>MathJax Test Page</title>
    <script type="text/javascript">
      function test() {
        alert(document.getElementsByTagName("p").length);
      };
    </script>
  </head>
  <body onload="test();">
    <p>test</p>
    <ml:foo xmlns:ml="http://foo"/>
  </body>
</html>
于 2012-11-27T19:43:24.363 に答える
1

@neirbowjの答えを拡張しますが、ET.ElementとET.SubElementを使用し、名前空間が混在するドキュメントをレンダリングします。ルートは明示的に名前空間化され、サブ要素(channel)がデフォルトの名前空間です。

# I set up but don't use the default namespace:
root = ET.Element('{http://www.w3.org/1999/02/22-rdf-syntax-ns#}RDF', nsmap={None: 'http://purl.org/rss/1.0/'})
# I use the default namespace by including its URL in curly braces:
e = ET.SubElement(root, '{http://purl.org/rss/1.0/}channel')
print(ET.tostring(root, xml_declaration=True, encoding='utf8').decode())

これにより、次のように出力されます。

<?xml version='1.0' encoding='utf8'?>
<rdf:RDF xmlns="http://purl.org/rss/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><channel/></rdf:RDF>

RDF名前空間に自動的にrdfを使用します。それがどのようにそれを理解するのかわかりません。それを指定したい場合は、ルート要素のnsmapに追加できます。

nsmap = {None: 'http://purl.org/rss/1.0/',
         'doge': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
root = ET.Element('{http://www.w3.org/1999/02/22-rdf-syntax-ns#}RDF', nsmap=nsmap)
e = ET.SubElement(root, '{http://purl.org/rss/1.0/}channel')
print(ET.tostring(root, xml_declaration=True, encoding='utf8').decode())

...そして私はこれを手に入れます:

<?xml version='1.0' encoding='utf8'?>
<doge:RDF xmlns:doge="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/"><channel/></doge:RDF>
于 2019-02-16T00:54:38.167 に答える