2012-01-18 2 views
2

Я пытаюсь добавить узел инструкции обработки в существующий документ XML, чтобы преобразование XSL было применено к документу при отображении в браузере. Я посмотрел, как это сделать, используя классы libxml++, но не смог найти его, поэтому я попытался использовать libxml2. Это то, что я придумал:Добавить инструкцию обработки в существующий документ XML, используя libxml ++

xmlpp::Document* Doc = Parser->get_document(); 

// Set processing instruction for stylesheet 
const xmlNodePtr PINode = xmlNewDocPI(
    Doc->cobj(), 
    reinterpret_cast<xmlChar*>("xml-stylesheet"), 
    reinterpret_cast<xmlChar*>("href=\"../stylesheet.xslt\" type=\"text/xsl\"") 
); 

if (PINode == NULL) { 
    // Never get here 
} 

Doc->write_to_file_formatted("mydoc.xml", "utf-8"); 

Узел инструкции по обработке не записан в документ. Так что мне здесь не хватает?

ответ

3

Оказалось, что просто позвонить xmlNewDocPI не достаточно. Он создает узел инструкции обработки и каким-то образом связывает его с документом, но фактически не прикрепляет его к документу.

Для этой цели некоторые из xmlAdd* функций должны быть вызваны и, так как мне нужно ПИ быть включено прямо под объявлением XML и не вложен в документах корневого узла, я должен был использовать следующее:

xmlAddPrevSibling(Doc->get_root_node()->cobj(), PINode); 

Он выглядит как хакерский, но работает. Таким образом, полный фрагмент кода для рабочего кода получает так:

xmlpp::Document* Doc = Parser->get_document(); 

// Set processing instruction for stylesheet 
const xmlNodePtr PINode = xmlNewDocPI(
    Doc->cobj(), 
    reinterpret_cast<xmlChar*>("xml-stylesheet"), 
    reinterpret_cast<xmlChar*>("href=\"../stylesheet.xslt\" type=\"text/xsl\"") 
); 

if (PINode != NULL) { 
    xmlAddPrevSibling(Doc->get_root_node()->cobj(), PINode); 
} 

Doc->write_to_file_formatted("mydoc.xml", "utf-8"); 
+0

Это не «хакерство», это правильный способ сделать это; вам нужно указать документ WHERE, чтобы поместить любой узел; инструкция по обработке потенциально может идти куда угодно. – Flynn1179

+0

Спасибо, что подтвердили, что это правильный способ сделать это. Я просто нашел * странным *, а не * hackish *, что местоположение узла PI должно было называться «предыдущим братом корневого узла». –

+0

О, я понимаю, что вы имеете в виду; Я имел в виду тот факт, что вы должны были добавить его вообще. Это распространенное заблуждение, что корневой элемент является корнем документа; сам документ на самом деле является узлом XML, а корневой элемент является его дочерним элементом. Если есть способ вставить инструкцию обработки в качестве первого дочернего документа самого документа, это также должно сделать это. «Корневой узел» не является строго точным, я считаю, что вы имеете в виду корневой элемент *. Я удивлен, что библиотека libxml использует «get_root_node», что вводит в заблуждение. Я знаю, что .NET использует «DocumentElement» для одного и того же. – Flynn1179

1

Добавление инструкции обработки в документе XML может быть сделано в чистом XSLT:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="/"> 
    <xsl:processing-instruction name="xml-stylesheet"> 
    <xsl:text>href="../stylesheet.xslt" type="text/xsl"</xsl:text> 
    </xsl:processing-instruction> 
    <xsl:text>&#xA;</xsl:text> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

, когда это преобразование применяется к любому XML документ, например, как показано ниже:

<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

разыскиваемый результат получают:

<?xml-stylesheet href="../stylesheet.xslt" type="text/xsl"?> 
<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 
+0

Thaks для вашего ответа, Dimitre. Это может быть обходным путем. –

+0

@ AntonioPrerez: Я рад, что вы нашли мой ответ полезным. Пожалуйста, отразите это через upvote/accept. Кроме того, обратите внимание, что это не «обходное решение», а главное * решение *. XSLT - это язык, специально разработанный для XML-преобразований, и превосходит любые другие технологии, которые не были разработаны с учетом XML-преобразований. –

+0

Дело в том, что мое приложение написано на C++ и предназначено для редактирования/создания XML-файлов. Я использую 'libxm ++' для этой цели, поэтому реализация вашего предлагаемого решения означает, что мне нужно будет хранить XSLT-код в файле или жестко закодировать и использовать библиотеку libxslt (или другую библиотеку), чтобы применить преобразование к файл.Для меня это обходное решение по сравнению с включением инструкции обработки в файл одновременно с редактированием его содержимого и невозможностью включить другую зависимость (библиотеку обработки XSLT). –

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