2015-04-24 2 views
2

Я пытаюсь сгенерировать XML из другого XML на основе некоторых определенных XPATH.Генерировать XML из некоторых определенных XPATH

XPATH:

country/name, 
country/org_id, 
country/lang, 
country/currency, 
generate_date, 
schedule/category/id, 
schedule/category/name, 
schedule/category/classes/class/id, 
schedule/category/classes/class/duration, 
schedule/category/classes/class/price, 
schedule/category/classes/class/instruction_language 

Xpath является исключением имени корневого узла, и это список.

XML:

<?xml version="1.0" encoding="utf-8" ?> 
<ou_schedule> 
    <country> 
    <name>Country Name</name> 
    <org_id>Org ID</org_id> 
    <lang>language</lang> 
    <currency>Currency</currency> 
    </country> 
    <generate_date>Date</generate_date> 
    <schedule> 
    <category> 
     <id>cat id</id> 
     <name>Cat name</name> 
     <classes> 
     <class> 
      <id>class id</id> 
      <duration>class duration</duration> 
      <price>price</price> 
      <instruction_language>Test Data</instruction_language> 
     </class> 
     <class> 
      <id>class id</id> 
      <duration>class duration</duration> 
      <price>price</price> 
      <instruction_language>Test Data</instruction_language> 
     </class> 
     </classes> 
    </category> 
    </schedule> 
</ou_schedule> 

Выход:

<?xml version="1.0" encoding="utf-8"?> 
<ou_schedule> 
    <country.name>country name</country.name> 
    <country.org_id>org id</country.org_id> 
    <country.lang>language</country.lang> 
    <country.currency>currency</country.currency> 
    <generate_date>date</generate_date> 
    <schedule.category.name>Cat Name</schedule.category.name> 
    <schedule.category.id>Cat ID</schedule.category.id> 
    <schedule.category.classes.class.id>class id</schedule.category.classes.class.id> 
    <schedule.category.classes.class.duration>class duration</schedule.category.classes.class.duration> 
    <schedule.category.classes.class.price>price</schedule.category.classes.class.price> 
    <schedule.category.classes.class.instruction_language>Test Data</schedule.category.classes.class.instruction_language> 

    <country.name>country name</country.name> 
    <country.org_id>org id</country.org_id> 
    <country.lang>language</country.lang> 
    <country.currency>currency</country.currency> 
    <generate_date>date</generate_date> 
    <schedule.category.name>Cat Name</schedule.category.name> 
    <schedule.category.id>Cat ID</schedule.category.id> 
    <schedule.category.classes.class.id>class id</schedule.category.classes.class.id> 
    <schedule.category.classes.class.duration>class duration</schedule.category.classes.class.duration> 
    <schedule.category.classes.class.price>price</schedule.category.classes.class.price> 
    <schedule.category.classes.class.instruction_language>Test Data</schedule.category.classes.class.instruction_language> 
</ou_schedule> 

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

Можно ли достичь этого с помощью какого-то общего XSLT?

+0

Какой другой формат, например? текст? JSON? – Alexander

+0

попробуйте XSLT преобразовать XML в другой формат. – Alexander

+0

Является ли этот список XPaths статичным, или он когда-нибудь изменится? - Обратите внимание, что вывод, который вы нам показываете, не является корректным XML (не имеет корневого элемента). –

ответ

2

Возможно ли достичь этого с помощью какого-то общего XSLT?

В случае, если есть два решения: один для XSLT 1.0 и один для XSLT 2.0, это может быть возможно (а искусственно) объединить их в одно целое, с использованием методов, как условная компиляция XSLT 2.0, которая будет исключать при «предварительно скомпилировать время» шаблоны и декларации решения XSLT 1.0. С другой стороны, решение XSLT 1.0 будет работать в режиме передовой совместимости и также будет иметь более высокий приоритет, указанный для его шаблонов (выше приоритета шаблона решения XSLT 2.0), поэтому шаблон решения XSLT 2.0 не будет выбран для когда преобразование выполняется с процессором XSLT 1.0.

Можно рассматривать это как интересное упражнение и следовать примеру в книге Майкла Кей «XSLT 2.0 и XPath 2.0», глава 3: «Структура таблиц стилей», раздел «Написание переносных таблиц стилей», подраздел «Условное Компиляция». Пример (в редакции у меня) на странице 128.


Вот короткий XSLT 2.0 решение (18 линий, если параметры значения опущены), чистые (без расширения функций), которые Безразлично 't использовать явные условные инструкции XSLT или любые xsl:variable.Даже функция tokenize() не используется:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 
<xsl:param name="pPaths" as="xs:string+" select= 
    "'country/name', 
    'country/org_id', 
    'country/lang', 
    'country/currency', 
    'generate_date', 
    'schedule/category/id', 
    'schedule/category/name', 
    'schedule/category/classes/class/id', 
    'schedule/category/classes/class/duration', 
    'schedule/category/classes/class/price', 
    'schedule/category/classes/class/instruction_language'"/> 

    <xsl:template match="/*"> 
    <xsl:copy><xsl:apply-templates/></xsl:copy> 
    </xsl:template> 

    <xsl:template match= 
    "*/*[string-join((ancestor::*[position() ne last()]| .)/name(), '/') = $pPaths]"> 
    <xsl:element 
     name="{string-join((ancestor::*[position() ne last()]|.)/name(), '.')}"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

Решение 2:

Здесь URI (Filepath) из ресурса (файла) передается в качестве параметра. Этот файл содержит все требуемые выражения XPath - каждый в отдельной строке.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 
<xsl:param name="pFilePath" select="'file:///C:/temp/expressions.txt'"/> 

<xsl:variable name="vExprs" select="tokenize(unparsed-text($pFilePath), '\r?\n')"/> 

    <xsl:template match="/*"> 
    <xsl:copy><xsl:apply-templates/></xsl:copy> 
    </xsl:template> 

    <xsl:template match= 
    "*/*[string-join((ancestor::*[position() ne last()]| .)/name(), '/') = $vExprs]"> 
    <xsl:element name= 
     "{string-join((ancestor::*[position() ne last()]|.)/name(), '.')}"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

Раствор 3:

Обе предыдущие решения могут быть дополнительно оптимизированы и упрощены, если для выражения входных XPath известно, что они выбирают элементы, которые имеют одного ребенка текстового узла (и это имеет место с первоначально предоставленными входными выражениями XPath и предоставлен исходный XML-документ):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 
<xsl:param name="pFilePath" select="'file:///C:/temp/expressions.txt'"/> 

<xsl:variable name="vExprs" select="tokenize(unparsed-text($pFilePath), '\r?\n')"/> 

    <xsl:template match="/*"> 
    <xsl:copy><xsl:apply-templates/></xsl:copy> 
    </xsl:template> 

    <xsl:template match= 
    "text()[string-join(ancestor::*[position() ne last()]/name(), '/') = $vExprs]"> 
    <xsl:element 
     name="{string-join(ancestor::*[position() ne last()]/name(), '.')}"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 
+0

@ michael.hor257k, Dimitre Novatchev: В моем представлении я пытаюсь выбрать самый глубокий узел элемента, а затем вернуть все его дочерние узлы и его узлы-предки. Поскольку формат XML не является фиксированным, и у меня есть только этот XPATH. Поэтому я пытаюсь преобразовать его в линейном формате. Является ли это возможным? – Beginner

+0

@Beginner, можно найти все самые глубокие элементы (может быть более одной с максимальной глубиной.Этот элемент может иметь только дочерний элемент текстового узла. Вы имеете в виду самый глубокий из элементов, выбранных выражением XPath? Что такое «это» в заявлении «Я пытаюсь преобразовать его в линейном формате»? –

+0

Да, самый глубокий узел элемента в списке xpath. Это означает xml. У меня есть только список xpath, и я хочу, чтобы структура XML была одинаковой как структура CSV. – Beginner

0

Моя первая мысль была: Интересно, здесь мы получим динамически построенное преобразование XSL. Но это не кажется достижимым, как объясняет dynamic xpath in xslt.

Итак, нужна вторая идея: вы можете подумать о преобразовании XSL в список выражений XPATH. В этом смысле нужно просто файл XSLT, как следующий

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <!-- the following select-attributes are the set of XPATH expressions 
     (relative to /ou_schedule/schedule/category/classes/class) --> 
    <xsl:template name="XPathList"> 
     <category_name> 
      <xsl:apply-templates select="ancestor::category/name"/> 
     </category_name> 

     <category_id> 
      <xsl:apply-templates select="ancestor::category/id"/> 
     </category_id> 

     <id> 
      <xsl:apply-templates select="id"/> 
     </id> 

     <duration> 
      <xsl:apply-templates select="duration"/> 
     </duration> 

     <price> 
      <xsl:apply-templates select="price"/> 
     </price> 

     <instruction_language> 
      <xsl:apply-templates select="instruction_language"/> 
     </instruction_language> 
    </xsl:template> 

    <!-- Basis --> 
    <xsl:template match="/"> 
     <ou_schedule> 
      <xsl:apply-templates select="//class"/> 
     </ou_schedule> 
    </xsl:template> 

    <xsl:template match="class"> 
     <xsl:copy> 
      <xsl:call-template name="XPathList"/> 
     </xsl:copy>  
    </xsl:template> 
</xsl:stylesheet> 

Ну, можно было бы написать это преобразование в более компактном виде. Но целью было перевести идею «иметь список XPATHs для преобразования XML» в код.

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