Как предотвратить экранирование символов в PHP XSLT?

0

У меня есть большой, сложный XML-документ, который нужно преобразовать дважды с помощью XSLT для достижения желаемого результата. Спасибо michael ответить здесь, я получил его, чтобы работать отлично, когда я выполнял преобразование локально (с xsltproc в терминале), но я не могу заставить его работать так же, как теперь, когда я переместил его на PHP.

Важная часть исходного документа выглядит так:

<BiographicalNote>
 &lt;p&gt;This text includes escaped HTML entities.&lt;/p&gt;
</BiographicalNote>

И желаемый результат:

<ParagraphStyleRange>
 <CharacterStyleRange>
  <Content>
   This text includes escaped HTML entities.
  </Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

Мне нужно сделать это преобразование в два этапа, потому что мне нужно unescape сущности HTML, а затем обрабатывать их как XML для применения дальнейших преобразований. Таким образом, первый шаг заботится о большей части трансформации, настраивая конечный документ, но когда дело доходит до секций с HTML, это делает только следующее:

<xsl:template match="BiographicalNote">
    <AuthorBio>
        <xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
    </AuthorBio>
</xsl:template>

Затем у меня есть второй XSLT, чтобы избавиться от тегов <p> и выполнять различные другие преобразования с тегами <em>, <b> и <span>:

<xsl:template match="AuthorBio">
 <ParagraphStyleRange>
  <xsl:apply-templates select="./node()"/>
  <Br/>
 </ParagraphStyleRange>
</xsl:template>

<xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
 <CharacterStyleRange>
  <Content><xsl:value-of select="."/></Content>
</CharacterStyleRange>  
</xsl:template>

Как я упоминал выше, это отлично работает, когда я преобразовываю его локально с помощью xsltproc. Но с PHP я получаю следующее:

<ParagraphStyleRange>
 <CharacterStyleRange>
  <Content>
   &lt;p&gt;This text includes escaped HTML entities.&lt;/p&gt;
  </Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

Я пробовал несколько вариантов кода PHP, но это то, что стало моим самым близким:

function processONIX () {
    // Load ONIX file
    $onix = new DOMDocument;
    $onix->load( 'HarbourONIX20141217.xml' );

    // Load ONIXtoICML XSL file
    $icml = new DOMDocument;
    $icml->load( 'ONIXtoICML.xsl' );

    // Configure the transformer
    $icmlproc = new XSLTProcessor;
    $icmlproc->importStyleSheet($icml);

    // Apply ONIXtoICML
    return $icmlproc->transformToDoc($onix);
}

function makeICML () {
    $temp = processONIX();

    // Load Inlines XSL file
    $inline = new DOMDocument;
    $inline->load( 'Inlines.xsl' );

    // Configure the transformer
    $inlineproc = new XSLTProcessor;
    $inlineproc->importStyleSheet($inline);

    // Apply Inlines
    $inlineproc->transformToURI($temp, 'ONIX.icml');
}

makeICML();
  • Это дает результат, как показано выше, при этом все биты HTML сбрасываются.
  • Использование transformToXML в processONIX() ничего мне не дает.
  • Использование transformToURI в processONIX успешно сохраняет файл, а теги HTML правильно экранированы: <AuthorBio><p>This text includes escaped HTML entities.</p></AuthorBio> Но когда я пытаюсь загрузить его как новый DOMDocument в makeICML() (так же, как в processONIX()), кажется, загружается как пустой документ. Не знаю, что здесь происходит.

Проблема, похоже, связана с функцией makeICML(), но это кажется странным, поскольку она почти точно такая же, как processONIX(), только с разными именами переменных и файлов. Я не могу понять, в какой момент символы ускользают, поэтому: как я могу это предотвратить?

Теги:
xslt
escaping

2 ответа

1

Атрибут disable-output-escaping является директивой для сериализатора и не имеет никакого эффекта, если вы не сериализуете вывод преобразования, то есть превращаете его в лексический XML. В вашем первом преобразовании вы используете transformToDoc(), который создает выход как дерево в памяти, минуя шаг сериализации. Таким образом, disable-output-escaping не влияет.

  • 0
    В таком случае, какова альтернатива? Как я уже упоминал в этом вопросе, я также попытался сохранить первый вывод в документе, используя transformToURI, а затем загрузить его на втором этапе в качестве нового документа DOMDocument. Промежуточный файл выглядит нормально, все символы правильно экранированы, но он загружается как пустой документ.
  • 0
    Тогда вы сделали что-то не так. Двухфазное преобразование, в котором промежуточный результат сериализуется как лексический XML, должно работать нормально.
0

У вас должна быть некоторая ошибка в частях кода, которые вы не поделили с вашим вопросом, так как при использовании этого исходного XML:

$source = <<<XML
<source>
<BiographicalNote>
 &lt;p&gt;This text includes escaped HTML entities.&lt;/p&gt;
</BiographicalNote>
</source>
XML;

и учитывая, что первая таблица стилей:

$xsltA = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="BiographicalNote">
        <AuthorBio>
            <xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
        </AuthorBio>
    </xsl:template>
</xsl:stylesheet>
XSLT;

и учитывая, что вторая таблица стилей:

$xsltB = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="AuthorBio">
         <ParagraphStyleRange>
              <xsl:apply-templates select="./node()"/>
              <Br/>
         </ParagraphStyleRange>
    </xsl:template>

    <xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
        <CharacterStyleRange>
            <Content><xsl:value-of select="."/></Content>
        </CharacterStyleRange>
    </xsl:template>
</xsl:stylesheet>
XSLT;

Выполнение приложения:

echo $source2 = Proc::create($xsltA)->transform($source), "\n----\n";
echo $source3 = Proc::create($xsltB)->transform($source2), "\n";

Результаты в следующем улучшенном выпуске:

<AuthorBio><p>This text includes escaped HTML entities.</p></AuthorBio>
----
<ParagraphStyleRange>
  <CharacterStyleRange>
    <Content>This text includes escaped HTML entities.</Content>
  </CharacterStyleRange>
  <Br/>
</ParagraphStyleRange>

Полный пример кода:

<?php
/**
 * http://stackoverflow.com/questions/27751339/how-do-i-prevent-character-escaping-in-php-xslt
 */

/**
 * Class Proc
 *
 * XSLT Processor
 */
class Proc
{
    private $proc;

    /**
     * @param string $xslt
     *
     * @return Proc
     */
    public static function create($xslt)
    {
        return new self($xslt);
    }

    public function __construct($xslt)
    {
        $proc = new XSLTProcessor();
        $proc->importStylesheet(
            $this->docFromString($xslt)
        );

        $this->proc = $proc;
    }

    public function transform($source)
    {
        $result = $this->proc->transformToDoc(
            $this->docFromString($source)
        );

        $result->formatOutput       = true;
        $result->preserveWhiteSpace = false;
        return $result->saveXML($result->documentElement);
    }

    private function docFromString($string)
    {
        $doc = new DOMDocument();
        $doc->loadXML($string);
        return $doc;
    }
}

$source = <<<XML
<source>
<BiographicalNote>
 &lt;p&gt;This text includes escaped HTML entities.&lt;/p&gt;
</BiographicalNote>
</source>
XML;

$xsltA = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="BiographicalNote">
        <AuthorBio>
            <xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
        </AuthorBio>
    </xsl:template>
</xsl:stylesheet>
XSLT;

$xsltB = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="AuthorBio">
         <ParagraphStyleRange>
              <xsl:apply-templates select="./node()"/>
              <Br/>
         </ParagraphStyleRange>
    </xsl:template>

    <xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
        <CharacterStyleRange>
            <Content><xsl:value-of select="."/></Content>
        </CharacterStyleRange>
    </xsl:template>
</xsl:stylesheet>
XSLT;

echo $source2 = Proc::create($xsltA)->transform($source), "\n----\n";
echo $source3 = Proc::create($xsltB)->transform($source2), "\n";
  • 0
    Спасибо за этот образец. Как я упоминал выше, преобразование отлично работает с xsltproc, поэтому я действительно не думаю, что с остальным кодом есть ошибка. В качестве теста я попробовал вариант вашего кода, загрузив XML и XSLT (те же сокращенные версии, которые вы использовали) в качестве новых DOMDocuments (и удалив бит docFromString), и он работал только наполовину. Это дало мне правильный результат первого преобразования, но ничего для второго. Есть идеи?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню