2009-03-23 2 views
1

Мне нужно обработать некоторый HTML-код, который имеет плохую структуру - например.XSLT: помогите мне исправить несколько тегов BODY

<html> 
<body>...</body> 
<body>...</body> 
</html> 

Какой самый лучший способ превратить этот HTML, так что содержимое второго тела появляются внутри первого, за исключением, конечно, дополнительный тег тела? Я не хочу ничего манипулировать этим правилом.

Я думал о совпадении в теге html и обрабатывал его там, используя явные вызовы с применением шаблонов, но для меня это кажется немного небрежным. Я знаю, как совместить ложные тела («body [position()> 1]»), но мне хотелось бы получить некоторые идеи о том, как лучше всего написать преобразование.

Редактировать: Мне нужно применить другие шаблоны для детей всех этих элементов, поэтому простая копия не будет работать.

И я хотел бы сохранить комментарии и инструкции по обработке. Я хочу почти весь документ как преобразование идентичности, за исключением этих нескольких тел и некоторых других незначительных изменений, которые я уже делаю успешно.

Редактировать 2: Важно сохранить дочерние элементы второго элемента тела в приведенном выше примере. Они должны быть дочерними элементами первого тега тела на выходе, в конце дочерних узлов первого тега тела.

Редактировать 3: Вот некоторый иллюстративный ввод/вывод (не проверяется на достоверность):

<html> 
    <!-- Look at my comments --> 
    <head> 
    <title>My title!</title> 
    <!-- Commentary --> 
    </head> 
    <body> 
    <p>Something <b>bold</b></p> 
    </body> 
    <body> 
    <!-- heh --> 
    <p>Some bozo put my parent in here.</p> 
    </body> 
    <body> 
    <p>More stuff here</p> 
    </body> 
</html> 

должны быть:

<html> 
    <!-- Look at my comments --> 
    <head> 
    <title>My title!</title> 
    <!-- Commentary --> 
    </head> 
    <body> 
    <p>Something <b>bold</b></p> 
    <!-- heh --> 
    <p>Some bozo put my parent in here.</p> 
    <p>More stuff here</p> 
    </body> 
</html> 

ответ

2

Добавить эти шаблоны идентичности преобразования:

<xsl:template match="/html/body[1]"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
     <xsl:apply-templates select="/html/body[2]/node() | /html/body[2]/@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/html/body"/> 

Edit:

Для пояса и-подтяжки об этом, вместо body[2] в вышеуказанном вы можете использовать body[position() != 1]. Это будет обрабатывать случай, когда ваш ввод содержит более двух элементов body.

+0

Пояс и подтяжки хороши, потому что есть как минимум три тега тела :) –

+0

Миссис Россни не поднимала никаких глупых детей. На самом деле это неправда, но это не я. –

1

Обычно избежать проблем, вниз по течению пути записи с учетом хаков будет результата в плохо управляемой кодовой базе.

Вы должны, скорее всего, отремонтировать сломанный HTML на своем источнике, , имеющий несколько тегов тела, как-то кажется серьезным недоразумением.

+0

К сожалению, в этом случае это действительно невозможно. –

1

Если вход HTML является хорошо сформированным XML, то этот шаблон XSLT бы это сделать:

<xsl:template match="/"> 
    <body> 
    <xsl:copy-of select="//body/node()" /> 
    </body> 
</xsl:template> 

(. Я не забочусь для <html> узла в этом примере, так как это тривиально)

более гибкий вариант выше (согласно запросу ФП в)

<!-- explicitly catching the initial html circumvents built-in templates --> 
<xsl:template match="/html"> 
    <xsl:copy> 
    <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<!-- copy everything that is not processed otherwise --> 
<xsl:template match="@*|node()|processing-instruction()"> 
    <xsl:copy-of select="." /> 
</xsl:template> 

<!-- matches any "body" node, but produces output only for the first --> 
<xsl:template match="body"> 
    <xsl:if test="not(preceding-sibling::body)"> 
    <xsl:copy> 
     <xsl:apply-templates select="//body/@*|//body/node()" /> 
    </xsl:copy> 
    </xsl:if> 
</xsl:template> 

<!-- you can add more of these specific templates, as needed --> 
<xsl:template match="body//a"> 
    <b> 
    <xsl:copy-of select="." /> 
    </b> 
</xsl:template> 

Этот вход:

<html> 
    <head><title>Foo!</title></head> 
    <?dummy processing instruction?> 
    <body foo="bar">...<a href="foo">asd</a><!-- comment --></body> 
    <body>...contents of body#2...</body> 
</html> 

получает меня этот результат (бело-пространство и отступы изменено для удобства чтения):

<html> 
    <head><title>Foo!</title></head> 
    <?dummy processing instruction?> 
    <body foo="bar"> 
    ... 
    <b><a href="foo">asd</a></b> 
    <!-- comment --> 
    ...contents of body#2... 
    </body> 
</html> 
+0

Я должен был сказать вам, что мне нужно применять другие шаблоны для детей тела. –

+0

Ну, используйте , затем. – Tomalak

+0

И голова, и комментарии и директивы обработки. Беда в том, что многого в исходном HTML-контексте, похоже, заставляет меня явно называть/применять вещи, которые я не хочу называть/применять, следовательно, «беспорядочно». –

-1

Если HTML является то, что испортил, то я бы не хотелось, чтобы предположить, что HTML хорошо формируется достаточно использовать xlst. Вы можете просто использовать регулярные выражения, чтобы найти

<body>(whitespace)</body> 

и удалите его.

+0

HTML обрабатывается TagSoup и, следовательно, является хорошо сформированным XML. –

1

Возможно, это ближе к тому, что вы после:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      version="2.0" exclude-result-prefixes="xsl"> 
<xsl:output indent="yes" method="html"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="@*|node()"/> 
</xsl:template> 

<!-- Identity Template --> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<!-- Matches on the first 'body' tag --> 
<xsl:template match="body[1]"> 
    <xsl:copy> 
     <!-- apply=templates the children of all the body tags --> 
     <xsl:apply-templates select="//body/node()"/> 
    </xsl:copy> 
</xsl:template> 

<!-- Skip processing on the subsequent body tags 
    (their children are still processed however) --> 
<xsl:template match="body"/> 

</xsl:stylesheet> 

Это использует популярный «толчок» структуру для шаблонов, так что вы могли бы найти его более гибким.

+0

Это близко к тому, что у меня есть, но я хочу держать детей других тегов тела, просто объединять их в конце первого. Я считаю, что эта таблица стилей удаляет их. –

+0

Обратите внимание, что использование «// body» находит все элементы тела в документе, а не только те, которые являются дочерними элементами элемента «html». –

+0

@Steven, хотя похоже, что это то, что он делает, присмотритесь. Поскольку мы применяем шаблоны, он копирует содержимое каждого элемента body. –

1

Я думаю @Keltex имел в виду, что вы должны вырезать

</body>\s*<body> 

перед обработкой документа, так что вы можете написать XSLT, как для нормированного входного сигнала.

Это то, что я сделал бы.

(Это предполагает, что несколько тегов тела не имеют никакого содержания между ними.)

EDIT: Это не будет удалять содержимое тегов тела. Обратите внимание, что вы удаляете что-либо из , закрывая тег тела, на , открывая. Это оставило бы на месте начальные и заключительные теги. Другими словами, с таким вводом

<body> 
    good stuff 
</body> 
<body> 
    more good stuff 
</body> 

Вы бы нацелились на эти два тега посередине. Удаление этого даст единое, непрерывное тело:

<body> 
    good stuff 
    more good stuff 
</body> 
+0

Но я хочу содержимое этих дополнительных тегов тела. Они отображаются в браузерах. –

+0

О, я неправильно понял, что вы говорили. Это идея. –

+0

Да, это было то, что я говорил. – Keltex

Смежные вопросы