Софт-Портал

как преобразовать Excel в Xml

Рейтинг: 4.5/5.0 (1035 проголосовавших)

Категория: Windows

Описание

Переход к OpenOffice: пакетное преобразование существующих документов

Переход к OpenOffice: пакетное преобразование существующих документов

Широко известно, что при помощи OpenOffice 2.0, открытой альтернативы пакету Microsoft Office, можно открывать файлы, созданные в Microsoft Office, и затем сохранять их в родном формате OpenOffice — zip-архиве, содержащем документ в виде XML-файла, соответствующего стандарту OpenDocument от OASIS. Таким образом можно преобразовывать в новый формат существующие документы Word, таблицы Excel и презентации PowerPoint. (В статье Opening Open Formats with XSLT на XML.com приводится пример простого приложения, использующего эти возможности: XSL -шаблон, который извлекает заголовки слайдов и заметки из файла с презентацией и сохраняет их в отдельный файл, который вы могли бы использовать как план своего выступления.) Более того, OpenOffice позволяет экспортировать все эти виды файлов в формат PDF.

Если вы собираетесь преобразовывать ваши файлы в новый формат по одному, то вам придётся открыть и заполнить несколько диалоговых окон для каждого файла. Если вам требуется преобразовать несколько сотен файлов, то такой подход окажется затруднительным. Что же делать, если у вас есть большая куча документов Word, таблиц Excel и презентаций PowerPoint, и вам нужно загрузить XML-версии всех файлов в одну базу данных, которая поддерживала бы запросы к содержимому этих XML-документов? Например, если вы — это штат Массачусетс или фирма IBM ?

Как и в продукте фирмы Microsoft, в OpenOffice есть макроязык. При запуске OpenOffice из командной строки Linux или Windows можно указывать, чтобы выполнился определённый макрос. Можно даже передать этому макросу в качестве параметра имя файла. Далее, если использовать ключ -invisible при запуске OpenOffice из командной строки, то его графический интерфейс (GUI) не будет отображаться. А если задействовать обе этих возможности вместе, то получится командная строка, которая преобразует файл Microsoft Office в файл OpenOffice (или в файл Acrobat) безо всякого GUI. Теперь, чтобы преобразовать сотню файлов, достаточно простого скрипта (например, на языке Perl), чтобы создать пакетный файл либо шелл-скрипт из сотни команд, каждая из которых преобразует один файл.

(Замечание: макросы, который вдохновили меня на создание этой статьи, явно были написаны для OpenOffice 1. x. — но тот макрос, который я из них собрал, был протестирован мной в OpenOffice 2.0 в Windows и в Linux.)

Создание макросов для преобразования

Все процедуры, которые понадобятся в ваших макросах, приведены ниже. Чтобы создать в OpenOffice модуль макросов и сохранить в него эти процедуры, выберите пункт меню Tools→Macros и затем Organize Macros, OpenOffice.org Basic, Organizer, New. Создастся новый модуль макросов. Назовите его MyConversions и закройте диалоговое окно.

Новый модуль будет отображаться в дереве макросов под именем /My Macros/Standard/MyConversions. как показано ниже:

Выберите модуль MyConversions и нажмите кнопку Edit. В появившемся скрипте строчки Sub Main и End Main служат шаблоном для будущего макроса. Замените их следующим кодом, после чего сохраните модуль:

Язык OpenOffice Basic похож на VBA — язык макросов в Microsoft Office; VBA похож на Visual Basic, а он, в свою очередь, — на тот самый BASIC, который для тех из нас, кто постарше, был первым изученным языком программирования. Я не углублялся ни в один из этих языков, но если вам что-то будет неясно в отношении их синтаксиса, то ответы достаточно легко находятся несколькими запросами к Google. Например, я совершенно не представлял себе, как записать оператор выбора в процедуре SaveAsOOO. но нашёл всю необходимую информацию с помощью Google и справки OpenOffice.

Весь код состоит из трёх процедур и одной функции. Процедура SaveAsPDF и функция MakePropertyValue взяты из сообщения на форуме OpenOffice. Процедура SaveAsDoc отличается от SaveAsPDF только параметром, передаваемым в MakePropertyValue. — названием фильтра экспорта. Если вы хотите добавить процедуры для сохранения таблиц OpenOffice в файлы Excel, или презентаций OpenOffice Impress в файлы PowerPoint, то всё что вам потребуется — взять копию одной из этих процедур и изменить в ней название фильтра экспорта и расширение нового файла.

Что замечательно в процедуре SaveAsOOO — это её универсальность. Вам не нужно определять, чем является входной файл — документом Word, таблицей Excel или презентацией PowerPoint, и не нужно указывать формат для нового файла. OpenOffice определит всё это сам. И как вы видите, единственное существенное отличие этой процедуры от SaveAsPDF — то, что я добавил код, определяющий для нового файла правильное расширение.

Запуск преобразования

Макросы можно запускать из командной строки вне зависимости от того, открыт ли в этот момент OpenOffice, или вы из него уже вышли. Примерно так должна выглядеть командная строка для преобразования файла Word в формат OpenOffice на компьютере с Windows, разбитая здесь на две строки:

На моём компьютере файл soffice.exe не находится в пути поиска исполняемых файлов, поэтому я вынужден указывать для него полный путь — заключённый в кавычки, потому что он содержит пробелы. Ключ -invisible указывает OpenOffice, что не нужно показывать экран с приветствием, создавать документ по умолчанию, и вообще отображать какой-либо GUI. (Чтобы увидеть список всех доступных ключей, попробуйте запустить soffice.exe из командной строки, задав единственный параметр -? ) Имя макроса указывается в виде, похожем на URL: сначала путь в дереве макросов до нужного макроса, затем параметр в скобках — имя файла, который требуется преобразовать. Указывать имя для нового файла не нужно — макрос выберет его сам в зависимости от исходного имени и выполняемого преобразования.

Поскольку макрос дописывает http:// в начало имени исходного файла, чтобы получить его URL, то это имя должно содержать полный путь к файлу, как показано в примере, — иначе вы получите сообщение об ошибке «Недопустимый URL».

В Linux в командной строке нужно указывать другое имя исполняемого файла. Установщик OpenOffice в моей Ubuntu поместил файл ooffice2 в путь поиска исполняемых файлов, так что мне не приходится указывать при его запуске полный путь. Я заключил вызов макроса в кавычки, потому что иначе находящиеся в нём скобки неправильно обрабатывались оболочкой. Во всех других отношениях те же самые макросы, что были созданы описанным выше способом, работали превосходно.

Я попытался преобразовать несколько разных файлов. Тестовый файл sample.doc лежит у меня уже несколько лет для испытания программ и сервисов, которые предлагают преобразовывать файлы Word в XML. В этом файле используются встроенные и пользовательские стили для абзацев и знаков, вложенные маркированные списки, изображение, таблица с объединёнными ячейками, вложенная таблица Excel, и ещё несколько вещей, на которых может споткнуться программа для преобразования. SaveAsOOO с этим файлом прекрасно справился.

Давайте преобразуем файлы MS Office

Теперь, когда у вас есть открытый многоплатформенный инструмент для преобразования новых и старых (по крайней мере, вплоть до Office 97) файлов MS Office в XML-документы открытого стандарта, как же лучше всего воспользоваться этим инструментом? Всё, что может запускаться из командной строки, может использоваться в пакетном режиме — без вмешательства пользователя. Можно создать Perl-скрипт, который бы принимал список входных файлов и создавал пакетный файл либо шелл-скрипт из последовательности команд, подобных приведённым выше, которые бы преобразовывали по одному файлу. Если то, что вам на самом деле нужно — сам XML-документ, то этот скрипт может заодно извлекать его из zip-архива, которым является файл OpenOffice, и переименовывать соответствующим образом. Шелл-скрипт, выполняющий всё это, выглядит так:

Пакетный файл для Windows:

Если вы собираетесь регулярно преобразовывать большое число документов, то запуск нового экземпляра OpenOffice для каждого преобразования будет существенно замедлять весь процесс. В Windows файл soffice.exe можно запустить в режиме «быстрого старта» (с ключом -quickstart ); тогда запускаемые после этого преобразования будут выполняться быстрее. Кроме этого, можно с помощью ключа -accept указать строку Universal Network Objects. которая позволила бы, используя API, управлять запущенным экземпляром OpenOffice из программы, написанной на C++, OpenOffice Basic, Python. Java или других языках. В этом случае можно было бы передавать имена документов для преобразования в запущенный экземпляр OpenOffice, используя вызовы API.

Наиболее интересной возможностью, которую предоставляет этот подход, мне кажется даже не преобразование присылаемых мне новых файлов Word и Excel в XML-формат OpenOffice, — а преобразование имеющихся старых документов. Сколько у вас есть старых файлов Microsoft Office? Сколько новых применений вы нашли бы содержащейся в них информации, если бы она была представлена в открытом и документированном XML-формате, и вы могли бы использовать для работы с этой информацией любые XML-инструменты? Учитывая, что всё это теперь возможно с использованием открытого программного обеспечения, работающего и в Windows, и в Linux, перед нами должны открываться огромные новые возможности.

XML.com Copyright © 1998-2007 O'Reilly Media, Inc.
Перевод: xmlhack.ru Copyright © 2000-2007 xmlhack.ru

как преобразовать excel в xml:

  • скачать
  • скачать
  • Другие статьи, обзоры программ, новости

    Как преобразовать XML в xls без установки MS Office 2003?

    Как преобразовать XML в xls без установки MS Office 2003?

    Есть ли какие-нибудь (желательно бесплатные) преобразователи, позволяющие переводить (или открывать) таблицы Micosoft Excel 2003 XML (с расширением .xml) в таблицы Excel (2000) с расширением .xls?Или как этому научить OpeOffice, чтобы он это делал стабильно - на некоторых файлах, присылаемых партнёрами, он безнадежно виснет?

    Excel: Как преобразовать XML в xls без установки MS Office 2003?

    В документе Wod есть множество отчетов в виде. шапочка, которая включает название источника, следующая строка -дата, следующая строка - тема, потом через ентер сам текст и ссылка. Вся шапочка выделена полужирным. Вот пример :Металоснабжение и сбыт12.04.13У итальянской Ilva новый генеральный директорНа прошлой неделе совет директоров крупнейшего итальянского металлургического завода Ilva назначил генеральным директором предприятия Энрико Бонди (Eico Bodi).Бруно Ферранте (Buo Feate), ранее занима.

    Уважаемые, у меня трабл :(есть 4 документа, созданные в одно время путем обычного "СОХРАНИТЬ КАК" одного из них. Дак вот. делаю на всех четырех документах в ПАРАМЕТРАХ СТРАНИЦЫ --- АЛЬБОМНАЯ  . 2 печатаются в альбомном виде, а два как не крути в книжном :( кто-нить мож отложил у себя в мозгах решение подобных проблем? гуглил сеня часа 2. но как понимаете ничего.
    2ЧЕЛ:нет комп один и тот же

    Есть таблица в формате Wod. Надо перенести в Excel.Доступные офисные пакеты: OOffice (предпочтительное), MS Office 2003, 2008
    В OOffice это не работает, вставляется как картинка. А нужны данные. А в MS Office нормально?

    164701 485425 517843

    ЦщЕ (Гость) 2 года назад

    Можно и без установки, берём для примера любой xml. Например, rss-рассылку.
    http://soundkey.ru/rss/zvukinews/
    открываем код, копируем, создаём файл с расширением .xls, вставляем данные туда
    меняем кодировку данных на windows-1251, в заголовке xml тоже прописываем такую кодировку
    \u003c?xml version\u003d"1.0" encoding\u003d"windows-1251"?

    Вот и всё, теперь этот файл может открыть почти любой эксель, возможно, сматерится на некорректность каких-нибудь данных, но откроет и покажет таблицей.

    Ответить на вопрос

    Преобразование xls в xml

    Преобразование xls в xml

    При выполнении преобразования xls в xml через команду Сохранить как - Данные XML, Excel потребует карту, и предложит Вам прочитать раздел Помощь. Читать помощь не будем, просто начнем делать.

    Создаем карту, используя таблицу как шаблон данных.
    Открываем обычный текстовый редактор создаем файл и наполняем его следующим образом:
    /* - этот символ набирать не нужно
    <?xml version="1.0"?>
    <?mso-application progid="Excel.Sheet"?>
    <vodonagrevateli>
    <offer>
    <Vendor>Ariston</Vendor>
    <name>ABS SGHP 80V SLIM</name>
    <price>170</price>
    <currencyId>USD</currencyId>
    <id>498</id>
    <category>100</category>
    <subcategory>272</subcategory>
    </offer>

    <offer>
    <Vendor>Ariston</Vendor>
    <name>SG UR 10</name>
    <price>95</price>
    <currencyId>USD</currencyId>
    <id>499</id>
    <category>100</category>
    <subcategory>272</subcategory>
    </offer>
    </vodonagrevateli>

    этот тоже не нужно набирать - */

    Как видно из примера, я описал первые две строки таблицы данных. Созданный текстовый документ сохранить и переименовать расширение из TXT в XML (пример имени: probnik.xml).
    Далее, открываем Excel, заходим в раздел "Данные" - "XML" - "Источник XML."
    В появившемся справа окне нажимаем кнопку "Карты XML" и выполняем процедуру Добавить, указывая путь к сохраненному ранее файлу probnik.xml.
    После добавления файла probnik.xml, в правом окне Вы должны увидеть дверовидную структуру.

    Дальнейшие действия носят чисто механический характер и не требуют размышления.
    Откройте новый лист в Excel-е, левой кнопкой мыши нажмите на значение "offer", после чего выделятся все элементы находящиеся внутри offer (Vendor, name, price и т.д.). Перетащите выделенное ячейку А1.


    Далее зайдите в файл с Вашими исходными данными, скопируйте весь массив данных, без первой строки (Производитель, название товара и т.д) и вставьте этот массив в синюю рамку в ячейку А2. Все ваши скопированные данные, должны будут находится внутри синей рамки.
    Затем зайдите в "Файл" - "Сохранить как", введите имя файла и выберите расширение XML-данные.

    Автор статьи будет признателен за ценные комментарии и отзывы, со стороны пользователей.

    Влад Самоделкин
    Эксперт СВ

    * - при копировании материала, ссылка на источник обязательна

    Преобразование массива в XML (экспорт таблицы в файл XML)

    Комментарии

    # 1 Valeri, 24 Мар 2014 - 17:42.

    Хотелось бы создавать Xml также из массива таблицы, верхние строки которой будут заголовками (подзаголовками)в несколько уровней?

    Например:
    1 Уровень <ФайлПФР>
    . 2 Уровень <ИмяФайла>.
    . 2 Уровень <ЗаголовокФайла>.
    . 2 Уровень <ПачкаВходящихДокументов.ДоставочнаяОрганизация="БАНК">
    . 3 Уровень <ВХОДЯЩАЯ.ОПИСЬ>.
    . 3 Уровень <СПИСОК.НА.ЗАЧИСЛЕНИЕ>
    . 4 Уровень <НомерВпачке>2
    . 4 Уровень <СведенияОполучателе>
    . 5 Уровень <НомерВмассиве>1
    . 5 Уровень <НомерВыплатногоДела>930158
    . 5 Уровень <КодРайона>016-001-000
    . 5 Уровень <СтраховойНомер>123-456-789.45
    . 6 Уровень <ФИО>
    . 7 Уровень <Фамилия>ИВАНОВ
    . 7 Уровень <Имя>ИВАН
    . 7 Уровень <Отчество>ИВАНОВИЧ

    К сожалению в настоящий момент не имею материальной возможности оформлять заказы, поэтому приходится только советы спрашивать, перебирать чужие коды и по форумам попрошайничать :(

    Здравствуйте, Valeri.
    Сделать-то всё можно, - но, скорее всего, макрос надо писать «с нуля» (а не переделывать какой-то готовый код)

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

    # 3 Valeri, 24 Мар 2014 - 16:31.

    Подскажите пжт можно ли сделать иерархические заголовки вашим методом (в три уровня)
    1 Уровень (Root)- Заголовок 1 >
    2 Уровень - Подзаголовок 1, Подзаголовок 2, Подзаголовок 3 >
    3 Уровень - Подподзаголок 1, Подподзаголок 2, Подподзаголок 3 и т.д. >
    > Ниже Элементы (массив)
    Спасибо

    # 4 Igor, 21 Мар 2014 - 16:27.

    Как получить dbf-таблицы из xls-файла при наличии групп в данных? (Михаил Дроздов

    Содержание:

    Вопрос действительно интересный. -) Схема получения dbf-таблиц могла бы быть следующей:

    1. получение xml- данных из xls- файла
    2. преобразование полученных xml- данных в структуру, пригодную для преобразований в связанные dbf- файлы
    3. ну и собственно преобразование xml- данных в dbf -таблицы, используя VFP- класс XMLAdapter

    Первый шаг может быть выполнен достаточно просто, если вы имеет Excel из MS Office 2003 (или выше). Чтобы выполнить второй шаг, на мой взгляд, проще всего воспользоваться технологией XSLT -преобразований, для чего следует хотя бы в общих чертах иметь представление об этой технологии. Другие пути для выполнения преобразований над xml -данными в использовании xml -парсеров и объектной модели DOM. также возможно написание кода обработки с использованием SAX2. Если у вас большие объёмы данных, то последнее выглядит наиболее предпочтительным. Наконец, чтобы воспользоваться VFP- классом XMLAdapter. появившемся в версии 8.0. вы должны быть обладателем именно версии VFP 9 .0 (или выше), т.к. в перелагаемом в этой статье VFP- коде, используется свойство XMLField.XMLNameIsXPath. Ниже предполагается, что все перечисленные условия удовлетворены.

    Итак, попробуем пройти все шаги, разбирая конкретный пример данных в MS Excel 2003. Допустим, что требуется получить dbf- таблицы для данных, которые в MS Excel выглядят так:

    Представленная таблица имеет "заголовок таблицы" (строки: 3-6), со строк: 7, 15. начинаются группы, а со строк: 8,13;16. начинаются соответствующие подгруппы. Каждая подгруппа помимо своего "заголовка" (строки: 8, 13, 16. ), имеет некоторое множество строк - "содержания подгруппы" (строки: 9-12,14,17-20. ).

    По этим данным, требуется получить три VFP- таблицы связанные отношениями:

    • для заголовков групп (назовём её group ),
    • для заголовков подгрупп (назовём её subgroup )
    • и наконец, для данных подгрупп (назовём её cells )

    Как было сказано выше, для этого средствами MS Excel 2003 (или выше), выделив соответствующую таблицу ( из файла: table.xls). выполним пункт меню: Файл/Сохранить как . [ Другие форматы/Тип файла: Таблица XML 2003 ].

    при этом, на возникший запрос о несоответствии формата следует ответить утвердительно. После чего мы получим файл с данными таблицы в xml- формате примерно такой структуры:

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

    • корневой элемент имеет "область имён" ( namespace ) "по умолчанию": xmlns="urn:schemas-microsoft-com:office:spreadsheet" .
    • собственно "сами данные" располагаются в элементах: /.//Workbook/Worksheet/Table/Row. а точнее в /.//Workbook/Worksheet/Table/Row/Cell/Data. в то время как значение атрибута ss:StyleID="s. " у элемента Cell позволяет достаточно чётко различать функциональную особенность данных элемента.

    К сожалению, наличие "области имён по умолчанию" делает невозможным использование таких средств как XSLT -преобразования. Поэтому первым шагом на нашем пути, удалим xmlns="urn:schemas-microsoft-com:office:spreadsheet" из корневого элемента Workbook , а полученный после такого редактирования файл сохраним с новым именем (из _table.xml в table.xml в нашем случае).

    Относительно "признаков выбора", требуемых нам "прикладных данных", глядя на содержимое полученного xml- файла, можно заметить следующее:

    • информация "о группах" располагается в таких элементах /.//Workbook/Worksheet/Table/Row/Cell/Data. у которых для элемента Cell атрибут ss:StyleID="s43"
    • в свою очередь, признаком выбора информации "о подгруппах" является значение этого атрибута ss:StyleID="s44"
    • наконец, элемент Row тогда содержит множество ячеек Cell содержащих "данные подгруппы", если среди них есть элемент Cell с атрибутом ss:StyleID="s42"

    Далее, мы постараемся воспользоваться этими обстоятельствами, чтобы организовать обработку данных с помощью XSLT- преобразования.

    Если вы уже имели опыт написания XSLT- преобразований, вам наверное известно, что всякий раз, когда требуется решить задачу, связанную "с организацией группировок в XSLT ", мы испытываем вполне ощутимые трудности. -( см. например, одно из решений здесь: http://xmlhack.ru/books/xslt/ch_11.html. В нашем случае, "на входе" мы имеем "линейную" последовательность элементов Row. тогда как "на выходе" т.е. в результате преобразований, нам требуется получить "вложенные" xml- структуры согласно связям типа: "родитель - > дети".

    Чтобы обеспечить это, воспользуемся перебором всего множества элементов из /.//Workbook/Worksheet/Table/Row с помощью XSLT -конструкции: <xsl:for-each>. организуя требуемую вложенность элементов их "динамическим формированием" в выходной поток. Что же конкретно нам нужно? Попробуем сформулировать:

    • всякий раз, когда "на входе" встречается элемент Row. содержащий в себе элемент Cell с атрибутом ss:StyleID="s43" . нам нужно "организовать начало новой группы" (закрыв прежде открытую, если такая имеется, естественно). В качестве имени для такого группового элемент возьмём название group .
    • в рамках групп, организованных с помощью предыдущего пункта, при обнаружении "на входе" в текущем Row элемента Cell с атрибутом ss:StyleID="s44" . нам следует организовать начало новой вложенной подгруппу (закрыв аналогичную предшествующую, если такая имеется). В качестве имени элемента для подгруппы возьмём subgroup .
    • по завершению цикла обработки всего множества элементов Row мы должны закрыть как подгруппу subgroup так и группу group. если они не были ещё закрыты.

    Здесь предполагается, что во входном потоке отсутствуют "разрывы" в смысле групп/подгрупп. Т.е. данные во входном потоке упорядочены в строгом соответствии с требованиями группировок, а также и то, что во входном потоке нет данных, не принадлежащих ни группам, ни их подгруппам. Основная трудность в реализации этой схемы заключается в проверке условий на момент открытия новой группы/подгруппы, позволяющих ответить на вопрос: а есть ли ранее открытые аналогичные группы/подгруппы, которые следует закрыть при открытии новых?

    При вышеупомянутых предположениях ответ на этот вопрос достаточно прост:

    • для самой внешней группы: закрытие группы следует выполнять всегда, если только это не первый раз встретившаяся группа.
    • для подгруппы ответ в общем-то аналогичный: закрытие подгруппы следует выполнять всегда, если это только не первая подгруппа в группе.

    Ниже XSTL -код, реализующий описанную схему:

    <? xml version = " 1.0 " encoding = " utf-8 " ?>

    < xsl:stylesheet version = " 1.0 "

    xmlns:o = " urn:schemas-microsoft-com:office:office "

    xmlns:x = " urn:schemas-microsoft-com:office:excel "

    xmlns:ss = " urn:schemas-microsoft-com:office:spreadsheet "

    xmlns:html = " http://www.w3.org/TR/REC-html40 "

    xmlns:msxsl = " urn:schemas-microsoft-com:xslt "

    xmlns:msdata = " urn:schemas-microsoft-com:xml-msdata "

    xmlns:xsl = " http://www.w3.org/1999/XSL/Transform "

    exclude-result-prefixes = " o x ss html xsl msxsl msdata " >

    < xsl:output method = " xml "

    encoding = " windows-1251 "

    version = " 1.0 "

    omit-xml-declaration = " yes " />

    < xsl:variable name = " varLft " >

    < xsl:text disable-output-escaping = " yes " > &#60; </ xsl:text >

    </ xsl:variable >

    < xsl:variable name = " varLft1 " >

    < xsl:text disable-output-escaping = " yes " > &#60; / </ xsl:text >

    </ xsl:variable >

    < xsl:variable name = " varRgt " >

    < xsl:text disable-output-escaping = " yes " > &#62; </ xsl:text >

    </ xsl:variable >

    < xsl:variable name = " varBegGroup " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft, 'group', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varEofGroup " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft1, 'group', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varBegSubGroup " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft, 'subgroup', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varEofSubGroup " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft1, 'subgroup', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varBegName " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft, 'name', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varEofName " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft1, 'name', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varBegId " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft, 'id', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varEofId " >

    < xsl:value-of disable-output-escaping = " yes " select = " concat($varLft1, 'id', $varRgt) " />

    </ xsl:variable >

    < xsl:variable name = " varFirstGrpID " >

    < xsl:value-of select = " generate-id(/.//Workbook/Worksheet/Table/Row/Cell[@ss:StyleID='s43']/..) " />

    </ xsl:variable >

    < xsl:template match = " / " >

    < xsl:text disable-output-escaping = " yes " ><![CDATA[ <?xml version="1.0" encoding="windows-1251"?> ]]></ xsl:text >

    < xsl:text disable-output-escaping = " yes " > &#xA; </ xsl:text >

    < xsl:attribute name = " form " >

    < xsl:value-of select = " normalize-space(/.//Workbook/Worksheet/Table/Row/Cell[@ss:StyleID='s23']/Data) " />

    </ xsl:attribute >

    < xsl:attribute name = " title " >

    < xsl:value-of select = " normalize-space(/.//Workbook/Worksheet/Table/Row/Cell[@ss:StyleID='s24']/Data) " />

    </ xsl:attribute >

    < xsl:for-each select = " /.//Workbook/Worksheet/Table/Row " >

    < xsl:if test = " Cell[@ss:StyleID='s43']/Data " >

    < xsl:if test = " generate-id()!=$varFirstGrpID " >

    <!-- </subgroup> -->

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofSubGroup " />

    <!-- </group> -->

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofGroup " />

    <!-- <group> -->

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegGroup " />

    < xsl:variable name = " varGroupName " >

    < xsl:value-of disable-output-escaping = " yes " select = " normalize-space(Cell[@ss:StyleID='s43']/Data) " />

    </ xsl:variable >

    < xsl:variable name = " varGroupID " >

    < xsl:value-of select = " generate-id() " />

    </ xsl:variable >

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegId " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varGroupID " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofId " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegName " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varGroupName " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofName " />

    <!-- // subgroup -->

    < xsl:if test = " Cell[@ss:StyleID='s44']/Data " >

    < xsl:if test = " string-length((preceding-sibling::*)[last()]/Cell[@ss:StyleID='s43']/Data)=0 " >

    <!-- </subgroup> -->

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofSubGroup " />

    <!-- <subgroup> -->

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegSubGroup " />

    < xsl:variable name = " varGroupName " >

    < xsl:value-of disable-output-escaping = " yes " select = " normalize-space(Cell[@ss:StyleID='s44']/Data) " />

    </ xsl:variable >

    < xsl:variable name = " varGroupID " >

    < xsl:value-of select = " generate-id() " />

    </ xsl:variable >

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegId " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varGroupID " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofId " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varBegName " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varGroupName " />

    < xsl:value-of disable-output-escaping = " yes " select = " $varEofName " />

    <!-- subgroup // -->

    </ xsl:stylesheet >

    • в переменные типа: varBegXXX / varEofXXX формируются строки-названий начал/концов элементов: <group/>, <subgroup/>, <name/>, <id/>
    • в переменную varFirstGrpID формируется уникальный код, соответствующий первому элементу Row. в котором имеется элемент <group/>
    • условие: test="string-length((preceding-sibling::*)[last()]/Cell[@ss:StyleID='s43']/Data)=0" проверяет: не является ли непосредственно предшествующий обработке элемент Row таким, который "открывает" группу <group/> ?
    • наконец, смысл шаблона для элемента Row в том, чтобы сформировать элемент <cells>. </cells> с включёнными в него элементами: d1. dN. каждый из которых содержит значения элементов Data. т.е. собственно "сами данные подгруппы".

    Фрагмент результата выполнения преобразования ConvertTable.xslt над файлом table.xml выглядит так:

    <? xml version = " 1.0 " encoding = " windows-1251 " ?>

    < root form = " Форма №7 " title = " Перечень работ кап. строительства на 2007 г. (без НДС, тыс.руб.) " >

    < id > IDAJL1P </ id >

    < name > 79.01 - СКРУ №1 </ name >

    < id > IDAOM1P </ id >

    < name > 01020000 - РУДНИК СКРУ-1 </ name >

    < d1 > 3 </ d1 >

    < d2 > ОАО СИЛЬВИНИТ, ШСУ </ d2 >

    < d3 > 1 </ d3 >

    < d4 > 0601011067 </ d4 >

    < d5 > ВСКРЫТИЕ И ПОДГОТОВКА ЗАПАСОВ НОВО-СОЛИКАМСКОГО УЧАСТКА ВКМКС РУДНИКОМ СКРУ-1 ОАО "СИЛЬВИНИТ" </ d5 >

    < d6 > 104440 </ d6 >

    < d7 > 29440 </ d7 >

    < d8 > 9480 </ d8 >

    < d9 > 75000 </ d9 >

    Фрагменты файла: out.xml

    Вот только теперь можно воспользоваться VFP- классом XMLAdapter для получения соответствующих dbf- файлов. Однако, в полученном нами xml- файле имеется небольшая проблема, заключающаяся в том, что информация по первичным ключам в данных для групп/подгрупп имеется (значения элементов <id>. </id>. динамически нами сформированных во время выполнения вышеприведённого XSLT- преобразования), в то время как внешние ключи ( foreign keys ) в xml- файле непосредственно отсутствуют. К счастью, гибкость VFP- класса XMLAdapter в версии 9.0 позволяет устранить эту проблему путём формирования как самих внешних ключей, так и их значений во время выполнения преобразования.

    Код, выполняющий подобное преобразование мог бы быть таким:

    CLOSE TABLES ALL

    LOCAL loXA as XMLAdapter

    loXA = NEWOBJECT ("XMLAdapter")

    CREATE CURSOR group ( id C(7), name C(120))

    CREATE CURSOR subgroup ( id C(7), name C(120), fk_id C(7))

    CREATE CURSOR cells (d1 I, d2 C(120), d3 I, d4 I, d5 C(120), d6 F(18,2), d7 I, d8 I, d9 F(18,2), fk_id C(7))

    loXA. RespectCursorCP == .T.

    На рисунке ниже представлен результат работы вышеприведённого кода:

    Используя XSLT -преобразования можно решить и обратную задачу: преобразование dbf- файла в xml- данные такой структуры, которые будут пригодны для просмотра из-под MS Excel 2003 (или выше). В простейшем случае, задача может быть решена за два шага:

    • получение из dbf -таблицы xml- файла, содержащего в себе встроенную (inline) XSD -схему
    • преобразование таким образом полученных xml -данных, в xml 2003 таблицу, используя XSLT -преобразование

    Проделаем это для фрагмента данных из dbf- таблицы, представленной на рисунке ниже:

    Первый шаг может быть решён использованием функции CursorToXML(). например таким VFP- кодом:

    # DEFINE DBF_FILE "spisok"

    SET DEFAULT TO ( LEFT ( SYS (16), RATC ("\", SYS (16))))

    IF. USED (DBF_FILE)

    в результате выполнения которого, получим вот такой xml -файл:

    <? xml version = " 1.0 " encoding = " Windows-1251 " standalone = " yes " ?>

    < VFPData xml:space = " preserve " >

    < xsd:schema id = " VFPData " xmlns:xsd = " http://www.w3.org/2001/XMLSchema " xmlns:msdata = " urn:schemas-microsoft-com:xml-msdata " >

    < xsd:element name = " VFPData " msdata:IsDataSet = " true " >

    < xsd:complexType >

    < xsd:choice maxOccurs = " unbounded " >

    < xsd:element name = " row " minOccurs = " 0 " maxOccurs = " unbounded " >

    < xsd:complexType >

    < xsd:attribute name = " kod_atc " type = " xsd:int " use = " required " />

    < xsd:attribute name = " raion " type = " xsd:int " use = " optional " />

    < xsd:attribute name = " name_atc " use = " optional " >

    < xsd:simpleType >

    < xsd:restriction base = " xsd:string " >

    < xsd:maxLength value = " 15 " />

    </ xsd:restriction >

    </ xsd:simpleType >

    </ xsd:attribute >

    < xsd:attribute name = " adr " use = " optional " >

    < xsd:simpleType >

    < xsd:restriction base = " xsd:string " >

    < xsd:maxLength value = " 50 " />

    </ xsd:restriction >

    </ xsd:simpleType >

    </ xsd:attribute >

    </ xsd:complexType >

    </ xsd:element >

    </ xsd:choice >

    < xsd:anyAttribute namespace = " http://www.w3.org/XML/1998/namespace " processContents = " lax " />

    </ xsd:complexType >

    </ xsd:element >

    </ xsd:schema >

    < row kod_atc = " 1 " raion = " 1 " name_atc = " ОПТС-31 " adr = " ул. Коноплянниковой, 4а " />

    < row kod_atc = " 2 " raion = " 1 " name_atc = " АТСК 33 " adr = " ул. Новоторжская, 18 " />

    < row kod_atc = " 3 " raion = " 1 " name_atc = " ОПТС-36 " adr = " ул. Склизкова, 36 " />

    < row kod_atc = " 4 " raion = " 1 " name_atc = " АТСК 100/2000 " adr = " пос. &quot; Сахарово &quot; " />

    < row kod_atc = " 5 " raion = " 1 " name_atc = " АТС &quot; ВНИИСВ &quot; " adr = " пос.Химинститутa " />

    < row kod_atc = " 6 " raion = " 1 " name_atc = " ПСК &quot; Южный &quot; " adr = " ПСК &quot; Южный &quot;. ПСК &quot; Чайка &quot; ,пр-т Победы,64 " />

    < row kod_atc = " 7 " raion = " 1 " name_atc = " ОПТС-32,34,50 " adr = " ул. Новоторжская, д.18 " />

    < row kod_atc = " 8 " raion = " 1 " name_atc = " ОПТС-43,45 " adr = " ул. Склизкова, 36 " />

    < row kod_atc = " 9 " raion = " 1 " name_atc = " ОПТС-(55-56) " adr = " ул.Оборонная,д.4 " />

    < row kod_atc = " 10 " raion = " 1 " name_atc = " OПТC-42,44 " adr = " ул. Баррикадная, д.8 " />

    Если теперь к полученному файлу spisok.XML применить вот такое XSLT -преобразование:

    <? xml version = " 1.0 " encoding = " windows-1251 " ?>

    <!-- file: convertToXslXml.xslt & see also: Q319180 "How to transform a DataSet to spreadsheet XML for Excel by using Visual Basic .NET and ASP.NET" -->

    < xsl:stylesheet version = " 1.0 "

    xmlns:xsl = " http://www.w3.org/1999/XSL/Transform "

    xmlns:msxsl = " urn:schemas-microsoft-com:xslt "

    xmlns:xsd = " http://www.w3.org/2001/XMLSchema "

    xmlns:msdata = " urn:schemas-microsoft-com:xml-msdata "

    xmlns:ss = " urn:schemas-microsoft-com:office:spreadsheet "

    exclude-result-prefixes = " xsl msxsl xsd msdata ss " >

    < xsl:output version = " 1.0 "

    method = " xml "

    encoding = " windows-1251 " />

    <!-- Выборка типа xsd:attribute из схемы по названию атрибута (@name) -->

    < xsl:key name = " rowType " match = " /VFPData/xsd:schema/xsd:element/xsd:complexType/xsd:choice/xsd:element/xsd:complexType/xsd:attribute " use = " @name " />

    <!-- Ряд параметров, значения которых можно переустановить перед обращением к преобразованию -->

    < xsl:param name = " prmLastAuthor " >

    < xsl:text > Michael </ xsl:text >

    < xsl:param name = " prmCreated " >

    < xsl:text > 2007-04-21T09:11:11Z </ xsl:text >

    < xsl:param name = " prmWorksheetName " >

    < xsl:text > spisok </ xsl:text >

    < xsl:template match = " / " >

    <!-- Выводим "заголовок" специфичный для MS Excel -->

    < xsl:text disable-output-escaping = " yes " ><![CDATA[ <?mso-application progid="Excel.Sheet"?> ]]></ xsl:text >

    < Workbook xmlns = " urn:schemas-microsoft-com:office:spreadsheet "

    xmlns:o = " urn:schemas-microsoft-com:office:office "

    xmlns:x = " urn:schemas-microsoft-com:office:excel "

    xmlns:ss = " urn:schemas-microsoft-com:office:spreadsheet "

    xmlns:html = " http://www.w3.org/TR/REC-html40 " >

    < DocumentProperties xmlns = " urn:schemas-microsoft-com:office:office " >

    < LastAuthor >

    < xsl:value-of select = " $prmLastAuthor " disable-output-escaping = " yes " />

    </ LastAuthor >

    < xsl:value-of select = " $prmCreated " disable-output-escaping = " yes " />

    < Version > 12.00 </ Version >

    </ DocumentProperties >

    < ExcelWorkbook xmlns = " urn:schemas-microsoft-com:office:excel " >

    < WindowHeight > 12345 </ WindowHeight >

    < WindowWidth > 18960 </ WindowWidth >

    < WindowTopX > 120 </ WindowTopX >

    < WindowTopY > 75 </ WindowTopY >

    < ProtectStructure > False </ ProtectStructure >

    < ProtectWindows > False </ ProtectWindows >

    </ ExcelWorkbook >

    < Style ss:ID = " Default " ss:Name = " Normal " >

    < Alignment ss:Vertical = " Bottom " />

    < Font ss:FontName = " Calibri " x:CharSet = " 204 " x:Family = " Swiss " ss:Size = " 11 "

    ss:Color = " #000000 " />

    < NumberFormat />

    < Protection />

    < Worksheet ss:Name = " <$prmWorksheetName> " >

    < Table ss:ExpandedColumnCount = " 256 " ss:ExpandedRowCount = " 11 " x:FullColumns = " 1 "

    x:FullRows = " 1 " ss:DefaultRowHeight = " 15 " >

    <!-- Выводим колонки (Column), взяв информацию из списка xsd:attribute в схеме, а также определяем приблизительное значение ss:Width для каждой из колонок -->

    < xsl:apply-templates select = " /./*/xsd:schema " />

    <!-- Выводим заголовки колонок, взяв информацию также из списка xsd:attribute в схеме. -->

    < xsl:apply-templates select = " /./*/xsd:schema/xsd:element/xsd:complexType/xsd:choice/xsd:element " mode = " flds " />

    <!--. наконец, выводим собственно содержание dbf-файла (т.е. данные из каждого элеменета <row />) -->

    < xsl:apply-templates select = " /./*/row " />

    <!-- Выводим "завершающий остаток" специфичный для MS Excel -->

    < WorksheetOptions xmlns = " urn:schemas-microsoft-com:office:excel " >

    < ProtectObjects > False </ ProtectObjects >

    < ProtectScenarios > False </ ProtectScenarios >

    </ WorksheetOptions >

    </ Worksheet >

    </ xsl:template >

    <!-- Выводим информацию для каждой колонки (Column) взяв информацию из списка xsd:attribute в схеме, а также определяем приблизительное значение ss:Width для каждой из колонок -->

    < xsl:template match = " xsd:attribute " >

    <!-- Пытаемся приблизительно определить длину обрабатываемой колонки -->

    < xsl:variable name = " varWidth " >

    < xsl:choose >

    < xsl:when test = " count(child::*)>0 and xsd:simpleType/xsd:restriction/xsd:maxLength/@value " >

    < xsl:value-of select = " number(xsd:simpleType/xsd:restriction/xsd:maxLength/@value)*10 " />

    < xsl:otherwise >

    < xsl:text > 20 </ xsl:text >

    </ xsl:otherwise >

    </ xsl:choose >

    </ xsl:variable >

    < Column ss:AutoFitWidth = " 0 " ss:Width = " <$varWidth> " xmlns = " urn:schemas-microsoft-com:office:spreadsheet " />

    </ xsl:template >

    <!-- Выводим заголовок текущей колонки, взяв информацию также из списка xsd:attribute в схеме. -->

    < xsl:template match = " xsd:element " mode = " flds " >

    < xsl:if test = " @name='row' " >

    < Row xmlns = " urn:schemas-microsoft-com:office:spreadsheet " >

    < xsl:for-each select = " xsd:complexType/xsd:attribute " >

    < Data ss:Type = " String " >

    < xsl:value-of select = " @name " />

    </ xsl:for-each >

    </ xsl:template >

    <!--. наконец, определяем вывод для каждого элемента <row />, т.е. собственно содержание dbf-файла -->

    < xsl:template match = " row " >

    < Row xmlns = " urn:schemas-microsoft-com:office:spreadsheet " >

    <!-- для каждого из атрибутов. -->

    < xsl:for-each select = " @* " >

    <!-- пытаемся выбрать его тип из схемы. -->

    < xsl:variable name = " varRowType " >

    < xsl:value-of select = " key('rowType',local-name())/@type " />

    </ xsl:variable >

    <!--. определяем текущий Excel-тип: либо как 'Number' (для xsd:int) или как 'String' в противном случае -->

    < xsl:variable name = " varType " >

    < xsl:choose >

    < xsl:when test = " $varRowType='xsd:int' " >

    < xsl:text > Number </ xsl:text >